diff --git a/platform/commonUI/browse/res/templates/browse-object.html b/platform/commonUI/browse/res/templates/browse-object.html index c3c1197bc8..366fcdb48b 100644 --- a/platform/commonUI/browse/res/templates/browse-object.html +++ b/platform/commonUI/browse/res/templates/browse-object.html @@ -57,7 +57,12 @@ + class="abs flex-elem grows object-holder-main scroll" + mct-selectable="{ + item: domainObject.useCapability('adapter'), + oldItem: domainObject + }" + mct-init-select> diff --git a/platform/commonUI/browse/res/templates/browse/inspector-region.html b/platform/commonUI/browse/res/templates/browse/inspector-region.html index 4106894c66..e558002995 100644 --- a/platform/commonUI/browse/res/templates/browse/inspector-region.html +++ b/platform/commonUI/browse/res/templates/browse/inspector-region.html @@ -19,12 +19,21 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> -
-
+
-
+ +
+ + +
+ +
+
diff --git a/platform/commonUI/browse/res/templates/browse/object-properties.html b/platform/commonUI/browse/res/templates/browse/object-properties.html index 142019dd60..5240e9f596 100644 --- a/platform/commonUI/browse/res/templates/browse/object-properties.html +++ b/platform/commonUI/browse/res/templates/browse/object-properties.html @@ -38,8 +38,6 @@ ng-class="{ last:($index + 1) === contextualParents.length }"> @@ -51,8 +49,6 @@ ng-class="{ last:($index + 1) === primaryParents.length }"> diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js index 521576b27c..45b5ec5ac2 100644 --- a/platform/commonUI/edit/bundle.js +++ b/platform/commonUI/edit/bundle.js @@ -121,7 +121,8 @@ define([ "key": "ElementsController", "implementation": ElementsController, "depends": [ - "$scope" + "$scope", + "openmct" ] }, { @@ -299,9 +300,6 @@ define([ { "key": "edit-elements", "template": elementsTemplate, - "uses": [ - "composition" - ], "gestures": [ "drop" ] @@ -385,7 +383,10 @@ define([ ] }, { - "implementation": EditToolbarRepresenter + "implementation": EditToolbarRepresenter, + "depends": [ + "openmct" + ] } ], "constants": [ diff --git a/platform/commonUI/edit/res/templates/edit-object.html b/platform/commonUI/edit/res/templates/edit-object.html index 995453519d..b6af8d9c86 100644 --- a/platform/commonUI/edit/res/templates/edit-object.html +++ b/platform/commonUI/edit/res/templates/edit-object.html @@ -61,7 +61,12 @@ + toolbar="toolbar" + mct-selectable="{ + item: domainObject.useCapability('adapter'), + oldItem: domainObject + }" + mct-init-select>
diff --git a/platform/commonUI/edit/res/templates/elements.html b/platform/commonUI/edit/res/templates/elements.html index 4746a81cf6..0edc447f7e 100644 --- a/platform/commonUI/edit/res/templates/elements.html +++ b/platform/commonUI/edit/res/templates/elements.html @@ -25,7 +25,7 @@ ng-model="filterBy">
-
diff --git a/platform/commonUI/edit/src/controllers/ElementsController.js b/platform/commonUI/edit/src/controllers/ElementsController.js index 6dd68c1269..7f77eab56a 100644 --- a/platform/commonUI/edit/src/controllers/ElementsController.js +++ b/platform/commonUI/edit/src/controllers/ElementsController.js @@ -29,7 +29,11 @@ define( * * @constructor */ - function ElementsController($scope) { + function ElementsController($scope, openmct) { + this.scope = $scope; + this.scope.composition = []; + var self = this; + function filterBy(text) { if (typeof text === 'undefined') { return $scope.searchText; @@ -47,10 +51,44 @@ define( } } + function setSelection(selection) { + self.scope.selection = selection; + self.refreshComposition(selection); + } + $scope.filterBy = filterBy; $scope.searchElements = searchElements; + + openmct.selection.on('change', setSelection); + setSelection(openmct.selection.get()); + + $scope.$on("$destroy", function () { + openmct.selection.off("change", setSelection); + }); } + /** + * Gets the composition for the selected object and populates the scope with it. + * + * @param selection the selection object + * @private + */ + ElementsController.prototype.refreshComposition = function (selection) { + if (!selection[0]) { + return; + } + + var selectedObjectComposition = selection[0].context.oldItem.useCapability('composition'); + + if (selectedObjectComposition) { + selectedObjectComposition.then(function (composition) { + this.scope.composition = composition; + }.bind(this)); + } else { + this.scope.composition = []; + } + }; + return ElementsController; } ); diff --git a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js index 756ae91f92..8fbfac292f 100644 --- a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js +++ b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js @@ -38,7 +38,7 @@ define( * @constructor * @implements {Representer} */ - function EditToolbarRepresenter(scope, element, attrs) { + function EditToolbarRepresenter(openmct, scope, element, attrs) { var self = this; // Mark changes as ready to persist @@ -109,6 +109,7 @@ define( this.updateSelection = updateSelection; this.toolbar = undefined; this.toolbarObject = {}; + this.openmct = openmct; // If this representation exposes a toolbar, set up watches // to synchronize with it. @@ -146,7 +147,7 @@ define( // Expose the toolbar object to the parent scope initialize(definition); // Create a selection scope - this.setSelection(new EditToolbarSelection()); + this.setSelection(new EditToolbarSelection(this.openmct)); // Initialize toolbar to an empty selection this.updateSelection([]); }; diff --git a/platform/commonUI/edit/src/representers/EditToolbarSelection.js b/platform/commonUI/edit/src/representers/EditToolbarSelection.js index 8c5e5b816e..f0690dce7b 100644 --- a/platform/commonUI/edit/src/representers/EditToolbarSelection.js +++ b/platform/commonUI/edit/src/representers/EditToolbarSelection.js @@ -38,10 +38,18 @@ define( * @memberof platform/commonUI/edit * @constructor */ - function EditToolbarSelection() { + function EditToolbarSelection(openmct) { this.selection = [{}]; this.selecting = false; this.selectedObj = undefined; + + openmct.selection.on('change', function (selection) { + if (selection[0] && selection[0].context.toolbar) { + this.select(selection[0].context.toolbar); + } else { + this.deselect(); + } + }.bind(this)); } /** diff --git a/platform/commonUI/edit/test/controllers/ElementsControllerSpec.js b/platform/commonUI/edit/test/controllers/ElementsControllerSpec.js index b9e98a839f..b99d46d0e2 100644 --- a/platform/commonUI/edit/test/controllers/ElementsControllerSpec.js +++ b/platform/commonUI/edit/test/controllers/ElementsControllerSpec.js @@ -27,11 +27,23 @@ define( describe("The Elements Pane controller", function () { var mockScope, + mockOpenMCT, + mockSelection, controller; beforeEach(function () { - mockScope = jasmine.createSpy("$scope"); - controller = new ElementsController(mockScope); + mockScope = jasmine.createSpyObj("$scope", ['$on']); + mockSelection = jasmine.createSpyObj("selection", [ + 'on', + 'off', + 'get' + ]); + mockSelection.get.andReturn([]); + mockOpenMCT = { + selection: mockSelection + }; + + controller = new ElementsController(mockScope, mockOpenMCT); }); function getModel(model) { diff --git a/platform/commonUI/edit/test/representers/EditToolbarRepresenterSpec.js b/platform/commonUI/edit/test/representers/EditToolbarRepresenterSpec.js index 83cb3c1235..34bcfb7af5 100644 --- a/platform/commonUI/edit/test/representers/EditToolbarRepresenterSpec.js +++ b/platform/commonUI/edit/test/representers/EditToolbarRepresenterSpec.js @@ -29,7 +29,9 @@ define( mockElement, testAttrs, mockUnwatch, - representer; + representer, + mockOpenMCT, + mockSelection; beforeEach(function () { mockScope = jasmine.createSpyObj( @@ -46,7 +48,18 @@ define( mockScope.$parent.$watchCollection.andReturn(mockUnwatch); + mockSelection = jasmine.createSpyObj("selection", [ + 'on', + 'off', + 'get' + ]); + mockSelection.get.andReturn([]); + mockOpenMCT = { + selection: mockSelection + }; + representer = new EditToolbarRepresenter( + mockOpenMCT, mockScope, mockElement, testAttrs diff --git a/platform/commonUI/edit/test/representers/EditToolbarSelectionSpec.js b/platform/commonUI/edit/test/representers/EditToolbarSelectionSpec.js index 074a5d229c..27e3230145 100644 --- a/platform/commonUI/edit/test/representers/EditToolbarSelectionSpec.js +++ b/platform/commonUI/edit/test/representers/EditToolbarSelectionSpec.js @@ -28,13 +28,25 @@ define( var testProxy, testElement, otherElement, - selection; + selection, + mockSelection, + mockOpenMCT; beforeEach(function () { testProxy = { someKey: "some value" }; testElement = { someOtherKey: "some other value" }; otherElement = { yetAnotherKey: 42 }; - selection = new EditToolbarSelection(); + mockSelection = jasmine.createSpyObj("selection", [ + // 'select', + 'on', + 'off', + 'get' + ]); + mockSelection.get.andReturn([]); + mockOpenMCT = { + selection: mockSelection + }; + selection = new EditToolbarSelection(mockOpenMCT); selection.proxy(testProxy); }); diff --git a/platform/commonUI/general/bundle.js b/platform/commonUI/general/bundle.js index 75f240d8c2..8d62185cc4 100644 --- a/platform/commonUI/general/bundle.js +++ b/platform/commonUI/general/bundle.js @@ -41,6 +41,7 @@ define([ "./src/controllers/BannerController", "./src/directives/MCTContainer", "./src/directives/MCTDrag", + "./src/directives/MCTSelectable", "./src/directives/MCTClickElsewhere", "./src/directives/MCTResize", "./src/directives/MCTPopup", @@ -90,6 +91,7 @@ define([ BannerController, MCTContainer, MCTDrag, + MCTSelectable, MCTClickElsewhere, MCTResize, MCTPopup, @@ -328,6 +330,13 @@ define([ "$document" ] }, + { + "key": "mctSelectable", + "implementation": MCTSelectable, + "depends": [ + "openmct" + ] + }, { "key": "mctClickElsewhere", "implementation": MCTClickElsewhere, diff --git a/platform/commonUI/general/res/sass/_fixed-position.scss b/platform/commonUI/general/res/sass/_fixed-position.scss index e2fcaaedf1..91b417aa87 100644 --- a/platform/commonUI/general/res/sass/_fixed-position.scss +++ b/platform/commonUI/general/res/sass/_fixed-position.scss @@ -25,6 +25,7 @@ } .l-fixed-position-item { + border-width: 1px; position: absolute; &.s-not-selected { opacity: 0.8; diff --git a/platform/commonUI/general/res/sass/edit/_editor.scss b/platform/commonUI/general/res/sass/edit/_editor.scss index b468d616b8..cd7939525b 100644 --- a/platform/commonUI/general/res/sass/edit/_editor.scss +++ b/platform/commonUI/general/res/sass/edit/_editor.scss @@ -80,23 +80,32 @@ // Editing Grids .l-grid-holder { - display: block; .l-grid { &.l-grid-x { @include bgTicks($colorGridLines, 'x'); } &.l-grid-y { @include bgTicks($colorGridLines, 'y'); } } } - // Prevent nested frames from showing their grids - .t-frame-outer .l-grid-holder { display: none !important; } - - // Prevent nested elements from showing s-hover-border - .t-frame-outer .s-hover-border { - border: none !important; + // Display grid when selected or selection parent. + .s-selected .l-grid-holder, + .s-selected-parent .l-grid-holder { + display: block; } - // Prevent nested frames from being selectable until we have proper sub-object editing - .t-frame-outer .t-frame-outer { - pointer-events: none; + // Display in nested frames... + .t-frame-outer { + // ...when drilled in or selection parent... + &.s-drilled-in, &.s-selected-parent { + .l-grid-holder { + display: block; + } + .t-frame-outer:not(.s-drilled-in) .l-grid-holder { + display: none; + } + } + // ...but hide otherwise. + .l-grid-holder { + display: none; + } } } diff --git a/platform/commonUI/general/res/sass/user-environ/_frame.scss b/platform/commonUI/general/res/sass/user-environ/_frame.scss index ea7fb0db22..b62d23f188 100644 --- a/platform/commonUI/general/res/sass/user-environ/_frame.scss +++ b/platform/commonUI/general/res/sass/user-environ/_frame.scss @@ -23,15 +23,14 @@ $ohH: $btnFrameH; $bc: $colorInteriorBorder; &.child-frame.panel { + border: 1px solid transparent; z-index: 0; // Needed to prevent child-frame controls from showing through when another child-frame is above &:not(.no-frame) { background: $colorBodyBg; - border: 1px solid $bc; - &:hover { - border-color: lighten($bc, 10%); - } + border-color: $bc; } } + .object-browse-bar { font-size: 0.75em; height: $ohH; @@ -92,9 +91,9 @@ &.no-frame { background: transparent !important; - border: none !important; + border: none; .object-browse-bar .right { - $m: 0; // $interiorMarginSm; + $m: 0; background: rgba(black, 0.3); border-radius: $basicCr; padding: $interiorMarginSm; @@ -104,7 +103,7 @@ } &.t-frame-outer > .t-rep-frame { &.contents { - $m: 2px; + $m: 0px; top: $m; right: $m; bottom: $m; @@ -115,6 +114,7 @@ display: none; } > .object-holder.abs { + overflow: hidden; top: 0 !important; } } diff --git a/platform/commonUI/general/res/sass/user-environ/_selecting.scss b/platform/commonUI/general/res/sass/user-environ/_selecting.scss index 525cfea7b2..52747529e6 100644 --- a/platform/commonUI/general/res/sass/user-environ/_selecting.scss +++ b/platform/commonUI/general/res/sass/user-environ/_selecting.scss @@ -20,35 +20,51 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ .s-hover-border { - border: 1px dotted transparent; + &:hover { + border-color: rgba($colorSelectableSelectedPrimary, 0.5) !important; + } } .s-status-editing { - // Limit to editing mode until we have sub-object selection + // Limit to editing mode + $o: 0.5; + $oHover: 0.8; + $bc: $colorSelectableSelectedPrimary; .s-hover-border { // Show a border by default so user can see object bounds and empty objects - border: 1px dotted rgba($colorSelectableSelectedPrimary, 0.3) !important; + border-color: rgba($bc, $o) !important; + border-style: dotted !important; + &:hover { - border-color: rgba($colorSelectableSelectedPrimary, 0.7) !important; + border-color: rgba($bc, $oHover) !important; + } + + &.t-object-type-layout { + border-style: dashed !important; } } - - .s-selected > .s-hover-border, - .s-selected.s-hover-border { - // Styles for a selected object. Also used by legacy Fixed Position/Panel objects. - border-color: $colorSelectableSelectedPrimary !important; - @include boxShdwLarge(); - // Show edit-corners if you got 'em - .edit-corner { - display: block; - &:hover { - background-color: rgba($colorKey, 1); + .s-selected { + &.s-moveable { + &:not(.s-drilled-in) { + cursor: move; } } } +} - .s-selected > .s-moveable, - .s-selected.s-moveable { - cursor: move; +.s-selected > .s-hover-border, +.s-selected.s-hover-border { + // Styles for a selected object. Also used by legacy Fixed Position/Panel objects. + border-color: $colorSelectableSelectedPrimary !important; + @include boxShdwLarge(); + // Show edit-corners if you got 'em + .edit-corner { + display: block; + &:hover { + background-color: rgba($colorKey, 1); + } } -} \ No newline at end of file +} + + + diff --git a/platform/commonUI/general/src/controllers/ObjectInspectorController.js b/platform/commonUI/general/src/controllers/ObjectInspectorController.js index d8e6ead840..eb6f122cc3 100644 --- a/platform/commonUI/general/src/controllers/ObjectInspectorController.js +++ b/platform/commonUI/general/src/controllers/ObjectInspectorController.js @@ -40,7 +40,7 @@ define( // Gets an array of the contextual parents/ancestors of the selected object function getContextualPath() { - var currentObj = $scope.ngModel.selectedObject, + var currentObj = $scope.domainObject, currentParent, parents = []; @@ -68,7 +68,7 @@ define( // If this the the initial call of this recursive function if (!current) { - current = $scope.ngModel.selectedObject; + current = $scope.domainObject; $scope.primaryParents = []; } @@ -87,16 +87,16 @@ define( // Gets the metadata for the selected object function getMetadata() { - $scope.metadata = $scope.ngModel.selectedObject && - $scope.ngModel.selectedObject.hasCapability('metadata') && - $scope.ngModel.selectedObject.useCapability('metadata'); + $scope.metadata = $scope.domainObject && + $scope.domainObject.hasCapability('metadata') && + $scope.domainObject.useCapability('metadata'); } // Set scope variables when the selected object changes - $scope.$watch('ngModel.selectedObject', function () { - $scope.isLink = $scope.ngModel.selectedObject && - $scope.ngModel.selectedObject.hasCapability('location') && - $scope.ngModel.selectedObject.getCapability('location').isLink(); + $scope.$watch('domainObject', function () { + $scope.isLink = $scope.domainObject && + $scope.domainObject.hasCapability('location') && + $scope.domainObject.getCapability('location').isLink(); if ($scope.isLink) { getPrimaryPath(); @@ -109,7 +109,7 @@ define( getMetadata(); }); - var mutation = $scope.ngModel.selectedObject.getCapability('mutation'); + var mutation = $scope.domainObject.getCapability('mutation'); var unlisten = mutation.listen(getMetadata); $scope.$on('$destroy', unlisten); } diff --git a/platform/commonUI/general/src/directives/MCTSelectable.js b/platform/commonUI/general/src/directives/MCTSelectable.js new file mode 100644 index 0000000000..f2f1dcc608 --- /dev/null +++ b/platform/commonUI/general/src/directives/MCTSelectable.js @@ -0,0 +1,60 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2017, 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 () { + + /** + * The mct-selectable directive allows selection functionality + * (click) to be attached to specific elements. + * + * @memberof platform/commonUI/general + * @constructor + */ + function MCTSelectable(openmct) { + + // Link; install event handlers. + function link(scope, element, attrs) { + var removeSelectable = openmct.selection.selectable( + element[0], + scope.$eval(attrs.mctSelectable), + attrs.hasOwnProperty('mctInitSelect') && scope.$eval(attrs.mctInitSelect) !== false + ); + + scope.$on("$destroy", function () { + removeSelectable(); + }); + } + + return { + // mct-selectable only makes sense as an attribute + restrict: "A", + // Link function, to install event handlers + link: link + }; + + } + + return MCTSelectable; + } +); diff --git a/platform/commonUI/general/test/controllers/ObjectInspectorControllerSpec.js b/platform/commonUI/general/test/controllers/ObjectInspectorControllerSpec.js index 4178fa8581..63ffb2e4e2 100644 --- a/platform/commonUI/general/test/controllers/ObjectInspectorControllerSpec.js +++ b/platform/commonUI/general/test/controllers/ObjectInspectorControllerSpec.js @@ -41,16 +41,6 @@ define( "$scope", ["$watch", "$on"] ); - mockScope.ngModel = {}; - mockScope.ngModel.selectedObject = { - getCapability: function () { - return { - listen: function () { - return true; - } - }; - } - }; mockObjectService = jasmine.createSpyObj( "objectService", @@ -77,22 +67,27 @@ define( "location capability", ["isLink"] ); + mockDomainObject.getCapability.andCallFake(function (param) { if (param === 'location') { return mockLocationCapability; } else if (param === 'context') { return mockContextCapability; + } else if (param === 'mutation') { + return { + listen: function () { + return true; + } + }; } }); + mockScope.domainObject = mockDomainObject; controller = new ObjectInspectorController(mockScope, mockObjectService); - - // Change the selected object to trigger the watch call - mockScope.ngModel.selectedObject = mockDomainObject; }); it("watches for changes to the selected object", function () { - expect(mockScope.$watch).toHaveBeenCalledWith('ngModel.selectedObject', jasmine.any(Function)); + expect(mockScope.$watch).toHaveBeenCalledWith('domainObject', jasmine.any(Function)); }); it("looks for contextual parent objects", function () { diff --git a/platform/commonUI/regions/bundle.js b/platform/commonUI/regions/bundle.js index ffe1822b65..318d403c27 100644 --- a/platform/commonUI/regions/bundle.js +++ b/platform/commonUI/regions/bundle.js @@ -38,7 +38,8 @@ define([ "implementation": InspectorController, "depends": [ "$scope", - "policyService" + "openmct", + "$document" ] } ], diff --git a/platform/commonUI/regions/src/InspectorController.js b/platform/commonUI/regions/src/InspectorController.js index d24475bd43..494ff7e368 100644 --- a/platform/commonUI/regions/src/InspectorController.js +++ b/platform/commonUI/regions/src/InspectorController.js @@ -21,44 +21,69 @@ *****************************************************************************/ define( - ['../../browse/src/InspectorRegion'], - function (InspectorRegion) { + [], + function () { /** - * The InspectorController adds region data for a domain object's type - * to the scope. + * The InspectorController listens for the selection changes and adds the selection + * object to the scope. * * @constructor */ - function InspectorController($scope, policyService) { - var domainObject = $scope.domainObject, - typeCapability = domainObject.getCapability('type'), - statusListener; + function InspectorController($scope, openmct, $document) { + var self = this; + self.$scope = $scope; /** - * Filters region parts to only those allowed by region policies - * @param regions - * @returns {{}} + * Callback handler for the selection change event. + * Adds the selection object to the scope. If the selected item has an inspector view, + * it puts the key in the scope. If provider view exists, it shows the view. */ - function filterRegions(inspector) { - //Dupe so we're not modifying the type definition. - return inspector.regions && inspector.regions.filter(function (region) { - return policyService.allow('region', region, domainObject); - }); + function setSelection(selection) { + if (selection[0]) { + var view = openmct.inspectorViews.get(selection); + var container = $document[0].querySelectorAll('.inspector-provider-view')[0]; + container.innerHTML = ""; + + if (view) { + self.providerView = true; + view.show(container); + } else { + self.providerView = false; + $scope.inspectorKey = selection[0].context.oldItem.getCapability("type").typeDef.inspector; + } + } + + self.$scope.selection = selection; } - function setRegions() { - $scope.regions = filterRegions(typeCapability.getDefinition().inspector || new InspectorRegion()); - } + openmct.selection.on("change", setSelection); + + setSelection(openmct.selection.get()); - statusListener = domainObject.getCapability("status").listen(setRegions); $scope.$on("$destroy", function () { - statusListener(); + openmct.selection.off("change", setSelection); }); - - setRegions(); } + /** + * Gets the selected item. + * + * @returns a domain object + */ + InspectorController.prototype.selectedItem = function () { + return this.$scope.selection[0].context.oldItem; + }; + + /** + * Checks if a provider view exists. + * + * @returns 'true' if provider view exists, 'false' otherwise + */ + InspectorController.prototype.hasProviderView = function () { + return this.providerView; + }; + return InspectorController; } ); diff --git a/platform/commonUI/regions/test/InspectorControllerSpec.js b/platform/commonUI/regions/test/InspectorControllerSpec.js index 7ade2c036f..6a94106fd1 100644 --- a/platform/commonUI/regions/test/InspectorControllerSpec.js +++ b/platform/commonUI/regions/test/InspectorControllerSpec.js @@ -27,82 +27,93 @@ define( describe("The inspector controller ", function () { var mockScope, mockDomainObject, - mockTypeCapability, - mockTypeDefinition, - mockPolicyService, - mockStatusCapability, - capabilities = {}, - controller; + mockOpenMCT, + mockSelection, + mockInspectorViews, + mockTypeDef, + controller, + container, + $document = [], + selectable = []; beforeEach(function () { - mockTypeDefinition = { - inspector: - { - 'regions': [ - {'name': 'Part One'}, - {'name': 'Part Two'} - ] - } + mockTypeDef = { + typeDef: { + inspector: "some-key" + } }; - mockTypeCapability = jasmine.createSpyObj('typeCapability', [ - 'getDefinition' - ]); - mockTypeCapability.getDefinition.andReturn(mockTypeDefinition); - capabilities.type = mockTypeCapability; - - mockStatusCapability = jasmine.createSpyObj('statusCapability', [ - 'listen' - ]); - capabilities.status = mockStatusCapability; - mockDomainObject = jasmine.createSpyObj('domainObject', [ 'getCapability' ]); - mockDomainObject.getCapability.andCallFake(function (name) { - return capabilities[name]; - }); - - mockPolicyService = jasmine.createSpyObj('policyService', [ - 'allow' - ]); + mockDomainObject.getCapability.andReturn(mockTypeDef); mockScope = jasmine.createSpyObj('$scope', - ['$on'] + ['$on', 'selection'] ); - mockScope.domainObject = mockDomainObject; + selectable[0] = { + context: { + oldItem: mockDomainObject + } + }; + + mockSelection = jasmine.createSpyObj("selection", [ + 'on', + 'off', + 'get' + ]); + mockSelection.get.andReturn(selectable); + + mockInspectorViews = jasmine.createSpyObj('inspectorViews', ['get']); + mockOpenMCT = { + selection: mockSelection, + inspectorViews: mockInspectorViews + }; + + container = jasmine.createSpy('container', ['innerHTML']); + $document[0] = jasmine.createSpyObj("$document", ['querySelectorAll']); + $document[0].querySelectorAll.andReturn([container]); + + controller = new InspectorController(mockScope, mockOpenMCT, $document); }); - it("filters out regions disallowed by region policy", function () { - mockPolicyService.allow.andReturn(false); - controller = new InspectorController(mockScope, mockPolicyService); - expect(mockScope.regions.length).toBe(0); + it("listens for selection change event", function () { + expect(mockOpenMCT.selection.on).toHaveBeenCalledWith( + 'change', + jasmine.any(Function) + ); + + expect(controller.selectedItem()).toEqual(mockDomainObject); + + var mockItem = jasmine.createSpyObj('domainObject', [ + 'getCapability' + ]); + mockItem.getCapability.andReturn(mockTypeDef); + selectable[0].context.oldItem = mockItem; + + mockOpenMCT.selection.on.mostRecentCall.args[1](selectable); + + expect(controller.selectedItem()).toEqual(mockItem); }); - it("does not filter out regions allowed by region policy", function () { - mockPolicyService.allow.andReturn(true); - controller = new InspectorController(mockScope, mockPolicyService); - expect(mockScope.regions.length).toBe(2); + it("cleans up on scope destroy", function () { + expect(mockScope.$on).toHaveBeenCalledWith( + '$destroy', + jasmine.any(Function) + ); + + mockScope.$on.calls[0].args[1](); + + expect(mockOpenMCT.selection.off).toHaveBeenCalledWith( + 'change', + jasmine.any(Function) + ); }); - it("Responds to status changes", function () { - mockPolicyService.allow.andReturn(true); - controller = new InspectorController(mockScope, mockPolicyService); - expect(mockScope.regions.length).toBe(2); - expect(mockStatusCapability.listen).toHaveBeenCalled(); - mockPolicyService.allow.andReturn(false); - mockStatusCapability.listen.mostRecentCall.args[0](); - expect(mockScope.regions.length).toBe(0); - }); - - it("Unregisters status listener", function () { - var mockListener = jasmine.createSpy('listener'); - mockStatusCapability.listen.andReturn(mockListener); - controller = new InspectorController(mockScope, mockPolicyService); - expect(mockScope.$on).toHaveBeenCalledWith("$destroy", jasmine.any(Function)); - mockScope.$on.mostRecentCall.args[1](); - expect(mockListener).toHaveBeenCalled(); + it("adds selection object to scope", function () { + expect(mockScope.selection).toEqual(selectable); + expect(controller.selectedItem()).toEqual(mockDomainObject); }); }); } diff --git a/platform/features/layout/bundle.js b/platform/features/layout/bundle.js index 4801dff7ae..25a3d81e29 100644 --- a/platform/features/layout/bundle.js +++ b/platform/features/layout/bundle.js @@ -260,7 +260,9 @@ define([ "key": "LayoutController", "implementation": LayoutController, "depends": [ - "$scope" + "$scope", + "$element", + "openmct" ] }, { diff --git a/platform/features/layout/res/templates/fixed.html b/platform/features/layout/res/templates/fixed.html index 57f2c08fb3..46cefb1ff5 100644 --- a/platform/features/layout/res/templates/fixed.html +++ b/platform/features/layout/res/templates/fixed.html @@ -40,7 +40,7 @@ 's-selected': controller.selected(element) }" ng-style="element.style" - ng-click="controller.select(element)"> + ng-click="controller.select(element, $event)"> @@ -53,14 +53,16 @@ mct-drag-down="controller.moveHandle().startDrag(controller.selected())" mct-drag="controller.moveHandle().continueDrag(delta)" mct-drag-up="controller.moveHandle().endDrag()" - ng-style="controller.selected().style"> + ng-style="controller.selected().style" + ng-click="$event.stopPropagation()">
+ mct-drag-up="handle.endDrag()" + ng-click="$event.stopPropagation()">
diff --git a/platform/features/layout/res/templates/layout.html b/platform/features/layout/res/templates/layout.html index 75643cc938..36d9431258 100644 --- a/platform/features/layout/res/templates/layout.html +++ b/platform/features/layout/res/templates/layout.html @@ -22,10 +22,12 @@
+ ng-click="controller.bypassSelection($event)"> -
+
@@ -34,10 +36,12 @@ ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }">
-
- + -
diff --git a/platform/features/layout/src/FixedController.js b/platform/features/layout/src/FixedController.js index fd6e0a284b..819fc26681 100644 --- a/platform/features/layout/src/FixedController.js +++ b/platform/features/layout/src/FixedController.js @@ -506,7 +506,11 @@ define( * Set the active user selection in this view. * @param element the element to select */ - FixedController.prototype.select = function select(element) { + FixedController.prototype.select = function select(element, event) { + if (event) { + event.stopPropagation(); + } + if (this.selection) { // Update selection... this.selection.select(element); diff --git a/platform/features/layout/src/LayoutController.js b/platform/features/layout/src/LayoutController.js index 445b1c9caf..aff192a6a3 100644 --- a/platform/features/layout/src/LayoutController.js +++ b/platform/features/layout/src/LayoutController.js @@ -27,9 +27,11 @@ */ define( [ + 'zepto', './LayoutDrag' ], function ( + $, LayoutDrag ) { @@ -50,10 +52,12 @@ define( * @constructor * @param {Scope} $scope the controller's Angular scope */ - function LayoutController($scope) { + function LayoutController($scope, $element, openmct) { var self = this, callbackCount = 0; + this.$element = $element; + // Update grid size when it changed function updateGridSize(layoutGrid) { var oldSize = self.gridSize; @@ -123,12 +127,11 @@ define( self.layoutPanels(ids); self.setFrames(ids); - // If there is a newly-dropped object, select it. - if (self.droppedIdToSelectAfterRefresh) { - self.select(null, self.droppedIdToSelectAfterRefresh); - delete self.droppedIdToSelectAfterRefresh; - } else if (composition.indexOf(self.selectedId) === -1) { - self.clearSelection(); + if (self.selectedId && + self.selectedId !== $scope.domainObject.getId() && + composition.indexOf(self.selectedId) === -1) { + // Click triggers selection of layout parent. + self.$element[0].click(); } } }); @@ -160,22 +163,39 @@ define( } }; + // Sets the selectable object in response to the selection change event. + function setSelection(selectable) { + var selection = selectable[0]; + + if (!selection) { + delete self.selectedId; + return; + } + + self.selectedId = selection.context.oldItem.getId(); + self.drilledIn = undefined; + self.selectable = selectable; + } + this.positions = {}; this.rawPositions = {}; this.gridSize = DEFAULT_GRID_SIZE; this.$scope = $scope; + this.drilledIn = undefined; + this.openmct = openmct; // Watch for changes to the grid size in the model $scope.$watch("model.layoutGrid", updateGridSize); - $scope.$watch("selection", function (selection) { - this.selection = selection; - }.bind(this)); - // Update composed objects on screen, and position panes $scope.$watchCollection("model.composition", refreshComposition); - // Position panes where they are dropped + openmct.selection.on('change', setSelection); + + $scope.$on("$destroy", function () { + openmct.selection.off("change", setSelection); + }); + $scope.$on("mctDrop", handleDrop); } @@ -357,37 +377,14 @@ define( }; /** - * Check if the object is currently selected. + * Checks if the object is currently selected. * * @param {string} obj the object to check for selection * @returns {boolean} true if selected, otherwise false */ LayoutController.prototype.selected = function (obj) { - return !!this.selectedId && this.selectedId === obj.getId(); - }; - - /** - * Set the active user selection in this view. - * - * @param event the mouse event - * @param {string} id the object id - */ - LayoutController.prototype.select = function (event, id) { - if (event) { - event.stopPropagation(); - if (this.selection) { - event.preventDefault(); - } - } - - this.selectedId = id; - - var selectedObj = {}; - selectedObj[this.frames[id] ? 'hideFrame' : 'showFrame'] = this.toggleFrame.bind(this, id); - - if (this.selection) { - this.selection.select(selectedObj); - } + var sobj = this.openmct.selection.get()[0]; + return (sobj && sobj.context.oldItem.getId() === obj.getId()) ? true : false; }; /** @@ -396,7 +393,7 @@ define( * @param {string} id the object id * @private */ - LayoutController.prototype.toggleFrame = function (id) { + LayoutController.prototype.toggleFrame = function (id, domainObject) { var configuration = this.$scope.configuration; if (!configuration.panels[id]) { @@ -404,21 +401,75 @@ define( } this.frames[id] = configuration.panels[id].hasFrame = !this.frames[id]; - this.select(undefined, id); // reselect so toolbar updates + + var selection = this.openmct.selection.get(); + selection[0].context.toolbar = this.getToolbar(id, domainObject); + this.openmct.selection.select(selection); // reselect so toolbar updates }; /** - * Clear the current user selection. + * Gets the toolbar object for the given domain object. + * + * @param id the domain object id + * @param domainObject the domain object + * @returns {object} + * @private */ - LayoutController.prototype.clearSelection = function () { + LayoutController.prototype.getToolbar = function (id, domainObject) { + var toolbarObj = {}; + toolbarObj[this.frames[id] ? 'hideFrame' : 'showFrame'] = this.toggleFrame.bind(this, id, domainObject); + return toolbarObj; + }; + + /** + * Bypasses selection if drag is in progress. + * + * @param event the angular event object + */ + LayoutController.prototype.bypassSelection = function (event) { if (this.dragInProgress) { + if (event) { + event.stopPropagation(); + } + return; + } + }; + + /** + * Checks if the domain object is drilled in. + * + * @param domainObject the domain object + * @return true if the object is drilled in, false otherwise + */ + LayoutController.prototype.isDrilledIn = function (domainObject) { + return this.drilledIn === domainObject.getId(); + }; + + /** + * Puts the given object in the drilled-in mode. + * + * @param event the angular event object + * @param domainObject the domain object + */ + LayoutController.prototype.drill = function (event, domainObject) { + if (event) { + event.stopPropagation(); + } + + if (!domainObject.getCapability('editor').inEditContext()) { return; } - if (this.selection) { - this.selection.deselect(); - delete this.selectedId; + if (!domainObject.hasCapability('composition')) { + return; } + + // Disable since fixed position doesn't use the selection API yet + if (domainObject.getModel().type === 'telemetry.fixed') { + return; + } + + this.drilledIn = domainObject.getId(); }; /** @@ -440,6 +491,36 @@ define( return this.gridSize; }; + /** + * Gets the selection context. + * + * @param domainObject the domain object + * @returns {object} the context object which includes + * item, oldItem and toolbar + */ + LayoutController.prototype.getContext = function (domainObject, toolbar) { + return { + item: domainObject.useCapability('adapter'), + oldItem: domainObject, + toolbar: toolbar ? this.getToolbar(domainObject.getId(), domainObject) : undefined + }; + }; + + /** + * Selects a newly-dropped object. + * + * @param classSelector the css class selector + * @param domainObject the domain object + */ + LayoutController.prototype.selectIfNew = function (selector, domainObject) { + if (domainObject.getId() === this.droppedIdToSelectAfterRefresh) { + setTimeout(function () { + $('.' + selector)[0].click(); + delete this.droppedIdToSelectAfterRefresh; + }.bind(this), 0); + } + }; + return LayoutController; } ); diff --git a/platform/features/layout/test/LayoutControllerSpec.js b/platform/features/layout/test/LayoutControllerSpec.js index 3ac4187b72..f6b16c052f 100644 --- a/platform/features/layout/test/LayoutControllerSpec.js +++ b/platform/features/layout/test/LayoutControllerSpec.js @@ -21,8 +21,14 @@ *****************************************************************************/ define( - ["../src/LayoutController"], - function (LayoutController) { + [ + "../src/LayoutController", + "zepto" + ], + function ( + LayoutController, + $ + ) { describe("The Layout controller", function () { var mockScope, @@ -32,7 +38,12 @@ define( controller, mockCompositionCapability, mockComposition, - mockCompositionObjects; + mockCompositionObjects, + mockOpenMCT, + mockSelection, + mockDomainObjectCapability, + $element = [], + selectable = []; function mockPromise(value) { return { @@ -58,21 +69,18 @@ define( } else { return {}; } + }, + getCapability: function () { + return mockDomainObjectCapability; + }, + hasCapability: function (param) { + if (param === 'composition') { + return id !== 'b'; + } } }; } - // Utility function to find a watch for a given expression - function findWatch(expr) { - var watch; - mockScope.$watch.calls.forEach(function (call) { - if (call.args[0] === expr) { - watch = call.args[1]; - } - }); - return watch; - } - beforeEach(function () { mockScope = jasmine.createSpyObj( "$scope", @@ -88,7 +96,6 @@ define( mockComposition = ["a", "b", "c"]; mockCompositionObjects = mockComposition.map(mockDomainObject); - testConfiguration = { panels: { a: { @@ -97,27 +104,70 @@ define( } } }; - + mockDomainObjectCapability = jasmine.createSpyObj('capability', + ['inEditContext'] + ); mockCompositionCapability = mockPromise(mockCompositionObjects); mockScope.domainObject = mockDomainObject("mockDomainObject"); mockScope.model = testModel; mockScope.configuration = testConfiguration; - mockScope.selection = jasmine.createSpyObj( - 'selection', - ['select', 'get', 'selected', 'deselect'] - ); + + selectable[0] = { + context: { + oldItem: mockScope.domainObject + } + }; + + mockSelection = jasmine.createSpyObj("selection", [ + 'select', + 'on', + 'off', + 'get' + ]); + mockSelection.get.andReturn(selectable); + mockOpenMCT = { + selection: mockSelection + }; + + $element = $('
'); + $(document).find('body').append($element); + spyOn($element[0], 'click'); spyOn(mockScope.domainObject, "useCapability").andCallThrough(); - controller = new LayoutController(mockScope); + controller = new LayoutController(mockScope, $element, mockOpenMCT); spyOn(controller, "layoutPanels").andCallThrough(); - findWatch("selection")(mockScope.selection); - jasmine.Clock.useMock(); }); + afterEach(function () { + $element.remove(); + }); + + + it("listens for selection change events", function () { + expect(mockOpenMCT.selection.on).toHaveBeenCalledWith( + 'change', + jasmine.any(Function) + ); + }); + + it("cleans up on scope destroy", function () { + expect(mockScope.$on).toHaveBeenCalledWith( + '$destroy', + jasmine.any(Function) + ); + + mockScope.$on.calls[0].args[1](); + + expect(mockOpenMCT.selection.off).toHaveBeenCalledWith( + 'change', + jasmine.any(Function) + ); + }); + // Model changes will indicate that panel positions // may have changed, for instance. it("watches for changes to composition", function () { @@ -320,67 +370,35 @@ define( .not.toEqual(oldStyle); }); - it("allows panels to be selected", function () { + it("allows objects to be selected", function () { + mockScope.$watchCollection.mostRecentCall.args[1](); + var childObj = mockCompositionObjects[0]; + selectable[0].context.oldItem = childObj; + mockOpenMCT.selection.on.mostRecentCall.args[1](selectable); + + expect(controller.selected(childObj)).toBe(true); + }); + + it("prevents event bubbling while drag is in progress", function () { mockScope.$watchCollection.mostRecentCall.args[1](); var childObj = mockCompositionObjects[0]; - controller.select(mockEvent, childObj.getId()); + // Do a drag + controller.startDrag(childObj.getId(), [1, 1], [0, 0]); + controller.continueDrag([100, 100]); + controller.endDrag(); + + // Because mouse position could cause the parent object to be selected, this should be ignored. + controller.bypassSelection(mockEvent); expect(mockEvent.stopPropagation).toHaveBeenCalled(); - expect(controller.selected(childObj)).toBe(true); - }); - - it("allows selection to be cleared", function () { - mockScope.$watchCollection.mostRecentCall.args[1](); - var childObj = mockCompositionObjects[0]; - - controller.select(null, childObj.getId()); - controller.clearSelection(); - - expect(controller.selected(childObj)).toBeFalsy(); - }); - - it("prevents clearing selection while drag is in progress", function () { - mockScope.$watchCollection.mostRecentCall.args[1](); - var childObj = mockCompositionObjects[0]; - var id = childObj.getId(); - - controller.select(mockEvent, id); - - // Do a drag - controller.startDrag(id, [1, 1], [0, 0]); - controller.continueDrag([100, 100]); - controller.endDrag(); - - // Because mouse position could cause clearSelection to be called, this should be ignored. - controller.clearSelection(); - - expect(controller.selected(childObj)).toBe(true); - - // Shoud be able to clear the selection after dragging is done. + // Shoud be able to select another object when dragging is done. jasmine.Clock.tick(0); - controller.clearSelection(); + mockEvent.stopPropagation.reset(); + controller.bypassSelection(mockEvent); - expect(controller.selected(childObj)).toBe(false); - }); - - it("clears selection after moving/resizing", function () { - mockScope.$watchCollection.mostRecentCall.args[1](); - var childObj = mockCompositionObjects[0]; - var id = childObj.getId(); - - controller.select(mockEvent, id); - - // Do a drag - controller.startDrag(id, [1, 1], [0, 0]); - controller.continueDrag([100, 100]); - controller.endDrag(); - - jasmine.Clock.tick(0); - controller.clearSelection(); - - expect(controller.selected(childObj)).toBe(false); + expect(mockEvent.stopPropagation).not.toHaveBeenCalled(); }); it("shows frames by default", function () { @@ -398,43 +416,74 @@ define( it("hides frame when selected object has frame ", function () { mockScope.$watchCollection.mostRecentCall.args[1](); var childObj = mockCompositionObjects[0]; - controller.select(mockEvent, childObj.getId()); - - expect(mockScope.selection.select).toHaveBeenCalled(); - - var selectedObj = mockScope.selection.select.mostRecentCall.args[0]; + selectable[0].context.oldItem = childObj; + mockOpenMCT.selection.on.mostRecentCall.args[1](selectable); + var toolbarObj = controller.getToolbar(childObj.getId(), childObj); expect(controller.hasFrame(childObj)).toBe(true); - expect(selectedObj.hideFrame).toBeDefined(); - expect(selectedObj.hideFrame).toEqual(jasmine.any(Function)); + expect(toolbarObj.hideFrame).toBeDefined(); + expect(toolbarObj.hideFrame).toEqual(jasmine.any(Function)); }); it("shows frame when selected object has no frame", function () { mockScope.$watchCollection.mostRecentCall.args[1](); - var childObj = mockCompositionObjects[1]; - controller.select(mockEvent, childObj.getId()); - - expect(mockScope.selection.select).toHaveBeenCalled(); - - var selectedObj = mockScope.selection.select.mostRecentCall.args[0]; + selectable[0].context.oldItem = childObj; + mockOpenMCT.selection.on.mostRecentCall.args[1](selectable); + var toolbarObj = controller.getToolbar(childObj.getId(), childObj); expect(controller.hasFrame(childObj)).toBe(false); - expect(selectedObj.showFrame).toBeDefined(); - expect(selectedObj.showFrame).toEqual(jasmine.any(Function)); + expect(toolbarObj.showFrame).toBeDefined(); + expect(toolbarObj.showFrame).toEqual(jasmine.any(Function)); }); - it("deselects the object that is no longer in the composition", function () { + it("selects the parent object when selected object is removed", function () { mockScope.$watchCollection.mostRecentCall.args[1](); var childObj = mockCompositionObjects[0]; - controller.select(mockEvent, childObj.getId()); + selectable[0].context.oldItem = childObj; + mockOpenMCT.selection.on.mostRecentCall.args[1](selectable); var composition = ["b", "c"]; mockScope.$watchCollection.mostRecentCall.args[1](composition); - expect(controller.selected(childObj)).toBe(false); + expect($element[0].click).toHaveBeenCalled(); }); + it("allows objects to be drilled-in only when editing", function () { + mockScope.$watchCollection.mostRecentCall.args[1](); + var childObj = mockCompositionObjects[0]; + childObj.getCapability().inEditContext.andReturn(false); + controller.drill(mockEvent, childObj); + + expect(controller.isDrilledIn(childObj)).toBe(false); + }); + + it("allows objects to be drilled-in only if it has sub objects", function () { + mockScope.$watchCollection.mostRecentCall.args[1](); + var childObj = mockCompositionObjects[1]; + childObj.getCapability().inEditContext.andReturn(true); + controller.drill(mockEvent, childObj); + + expect(controller.isDrilledIn(childObj)).toBe(false); + }); + + it("selects a newly-dropped object", function () { + mockScope.$on.mostRecentCall.args[1]( + mockEvent, + 'd', + { x: 300, y: 100 } + ); + + var childObj = mockDomainObject("d"); + var testElement = $("
"); + $element.append(testElement); + spyOn(testElement[0], 'click'); + + controller.selectIfNew('some-class', childObj); + jasmine.Clock.tick(0); + + expect(testElement[0].click).toHaveBeenCalled(); + }); }); } ); diff --git a/platform/features/table/bundle.js b/platform/features/table/bundle.js index fdebd5cc2f..bb67f9f900 100644 --- a/platform/features/table/bundle.js +++ b/platform/features/table/bundle.js @@ -69,7 +69,7 @@ define([ "delegates": [ "telemetry" ], - "inspector": tableInspector, + "inspector": "table-options-edit", "contains": [ { "has": "telemetry" diff --git a/platform/features/table/res/templates/table-options-edit.html b/platform/features/table/res/templates/table-options-edit.html index 9cff7664e1..0233e003f3 100644 --- a/platform/features/table/res/templates/table-options-edit.html +++ b/platform/features/table/res/templates/table-options-edit.html @@ -19,7 +19,10 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> -
+ +
Table Options 0) { + return providers[0].view(selection); + } + }; + + /** + * @private + */ + InspectorViewRegistry.prototype.getAllProviders = function () { + return Object.values(this.providers); + }; + + /** + * Registers a new type of view. + * + * @param {module:openmct.InspectorViewRegistry} provider the provider for this view + * @method addProvider + * @memberof module:openmct.InspectorViewRegistry# + */ + InspectorViewRegistry.prototype.addProvider = function (provider) { + var key = provider.key; + + if (key === undefined) { + throw "View providers must have a unique 'key' property defined"; + } + + if (this.providers[key] !== undefined) { + console.warn("Provider already defined for key '%s'. Provider keys must be unique.", key); + } + + this.providers[key] = provider; + }; + + /** + * @private + */ + InspectorViewRegistry.prototype.getByProviderKey = function (key) { + return this.providers[key]; + }; + + /** + * A View is used to provide displayable content, and to react to + * associated life cycle events. + * + * @name View + * @interface + * @memberof module:openmct + */ + + /** + * Populate the supplied DOM element with the contents of this view. + * + * View implementations should use this method to attach any + * listeners or acquire other resources that are necessary to keep + * the contents of this view up-to-date. + * + * @param {HTMLElement} container the DOM element to populate + * @method show + * @memberof module:openmct.View# + */ + + /** + * Release any resources associated with this view. + * + * View implementations should use this method to detach any + * listeners or release other resources that are no longer necessary + * once a view is no longer used. + * + * @method destroy + * @memberof module:openmct.View# + */ + + /** + * Exposes types of views in inspector. + * + * @interface InspectorViewProvider + * @property {string} key a unique identifier for this view + * @property {string} name the human-readable name of this view + * @property {string} [description] a longer-form description (typically + * 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) + * @memberof module:openmct + */ + + /** + * Checks if this provider can supply views for a selection. + * + * @method canView + * @memberof module:openmct.InspectorViewProvider# + * @param {module:openmct.selection} selection + * @returns {boolean} 'true' if the view applies to the provided selection, + * otherwise 'false'. + */ + + /** + * Provides a view of the selection object in the inspector. + * + * @method view + * @memberof module:openmct.InspectorViewProvider# + * @param {module:openmct.selection} selection the selection object + * @returns {module:openmct.View} a view of this selection + */ + + return InspectorViewRegistry; +});