mirror of
https://github.com/nasa/openmct.git
synced 2024-12-19 05:07:52 +00:00
[Layout] Support sub-object selection in layout (#1811)
Updates to sub object selection, first cut of selection APIs. * [API] Add inspector view registry to register inspector view providers and show a view in the inspector. [API] Modify the selection API to register the click event and handle the event. The API will add a class to the selected object and the immediate parent of the selected object. [Directive] Implemenet mct-selectable directive for making an element selectable. [Layout] Update the layout controller to use the Selection API. Also, add double click gesture to allow drilling into a selected object. Populate the Elements pool with contained elements of the selected object. Update toolbar and inspector to listen for the changes in selection. * [Frontend] Mods to markup and CSS for sub-object selection * MCTSelectable allows selection in initialization, use to select on navigation [Frontend] Show grid in first nested layout, hide from deeper nesting. Only show grids when applicable to relative selection. * Fix checkstyle and lint errors * Bring back the change that made mct-init-select work * [Inspector] Make sure the right content is displayed based on whether a view provider exists or not. * Only show table options when editing * Make reviewers' requested changes * Fix broken tests * [Frontend] Cleanups and tweaks Fixes #1811 - Cleanups between frame, editor and selecting.scss; - Hover and selected borders visually pumped up a bit; - Solid borders on hover and selecting when browsing; - Dashed borders for layouts when editing; - Fixed cursor to only show move capability when element is selected; * [Frontend] Tweaks to frame.no-frame layout Fixes #1811 - Margin set to 0; - Overflow set to hidden; * [Frontend] Fixed position items border width fixed Fixes #1811 - Set to 1px; * Add tests for inspector controller and fix broken tests. Clean up code. * [Fixed Position] Stop event propagation on click handlers in fixed position to avoid the event reaching the selection click handlers which caused issues with toolbar and selection." * Fix tests * Add tests * Add test * Remove element from document
This commit is contained in:
parent
50b4d5cb28
commit
425655bae0
@ -57,7 +57,12 @@
|
||||
</div>
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs flex-elem grows object-holder-main scroll">
|
||||
class="abs flex-elem grows object-holder-main scroll"
|
||||
mct-selectable="{
|
||||
item: domainObject.useCapability('adapter'),
|
||||
oldItem: domainObject
|
||||
}"
|
||||
mct-init-select>
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,12 +19,21 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-controller="InspectorController">
|
||||
<div ng-repeat="region in regions">
|
||||
<div ng-controller="InspectorController as controller">
|
||||
<mct-representation
|
||||
key="region.content.key"
|
||||
mct-object="domainObject"
|
||||
key="'object-properties'"
|
||||
mct-object="controller.selectedItem()"
|
||||
ng-model="ngModel">
|
||||
</mct-representation>
|
||||
</div>
|
||||
|
||||
<div ng-if="!controller.hasProviderView()">
|
||||
<mct-representation
|
||||
key="inspectorKey"
|
||||
mct-object="controller.selectedItem()"
|
||||
ng-model="ngModel">
|
||||
</mct-representation>
|
||||
</div>
|
||||
|
||||
<div class='inspector-provider-view'>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,8 +38,6 @@
|
||||
ng-class="{ last:($index + 1) === contextualParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
@ -51,8 +49,6 @@
|
||||
ng-class="{ last:($index + 1) === primaryParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
|
@ -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": [
|
||||
|
@ -61,7 +61,12 @@
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs flex-elem grows object-holder-main scroll"
|
||||
toolbar="toolbar">
|
||||
toolbar="toolbar"
|
||||
mct-selectable="{
|
||||
item: domainObject.useCapability('adapter'),
|
||||
oldItem: domainObject
|
||||
}"
|
||||
mct-init-select>
|
||||
</mct-representation>
|
||||
</div><!--/ l-object-wrapper-inner -->
|
||||
</div>
|
||||
|
@ -25,7 +25,7 @@
|
||||
ng-model="filterBy">
|
||||
</mct-include>
|
||||
<div class="flex-elem grows vscroll">
|
||||
<ul class="tree">
|
||||
<ul class="tree" ng-if="composition.length > 0">
|
||||
<li ng-repeat="containedObject in composition | filter:searchElements">
|
||||
<span class="tree-item">
|
||||
<mct-representation
|
||||
@ -36,5 +36,6 @@
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-if="composition.length === 0">No contained elements</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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;
|
||||
}
|
||||
);
|
||||
|
@ -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([]);
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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,
|
||||
|
@ -25,6 +25,7 @@
|
||||
}
|
||||
|
||||
.l-fixed-position-item {
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
&.s-not-selected {
|
||||
opacity: 0.8;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
60
platform/commonUI/general/src/directives/MCTSelectable.js
Normal file
60
platform/commonUI/general/src/directives/MCTSelectable.js
Normal file
@ -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;
|
||||
}
|
||||
);
|
@ -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 () {
|
||||
|
@ -38,7 +38,8 @@ define([
|
||||
"implementation": InspectorController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"policyService"
|
||||
"openmct",
|
||||
"$document"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -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;
|
||||
}
|
||||
);
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -260,7 +260,9 @@ define([
|
||||
"key": "LayoutController",
|
||||
"implementation": LayoutController,
|
||||
"depends": [
|
||||
"$scope"
|
||||
"$scope",
|
||||
"$element",
|
||||
"openmct"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -40,7 +40,7 @@
|
||||
's-selected': controller.selected(element)
|
||||
}"
|
||||
ng-style="element.style"
|
||||
ng-click="controller.select(element)">
|
||||
ng-click="controller.select(element, $event)">
|
||||
<mct-include key="element.template"
|
||||
parameters="{ gridSize: controller.getGridSize() }"
|
||||
ng-model="element">
|
||||
@ -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()">
|
||||
</div>
|
||||
<div ng-repeat="handle in controller.handles()"
|
||||
class="l-fixed-position-item-handle edit-corner"
|
||||
ng-style="handle.style()"
|
||||
mct-drag-down="handle.startDrag()"
|
||||
mct-drag="handle.continueDrag(delta)"
|
||||
mct-drag-up="handle.endDrag()">
|
||||
mct-drag-up="handle.endDrag()"
|
||||
ng-click="$event.stopPropagation()">
|
||||
</div>
|
||||
</span>
|
||||
|
||||
|
@ -22,10 +22,12 @@
|
||||
|
||||
<div class="abs l-layout"
|
||||
ng-controller="LayoutController as controller"
|
||||
ng-click="controller.clearSelection()">
|
||||
ng-click="controller.bypassSelection($event)">
|
||||
|
||||
<!-- Background grid -->
|
||||
<div class="l-grid-holder" ng-click="controller.clearSelection()">
|
||||
<div class="l-grid-holder"
|
||||
ng-show="!controller.drilledIn"
|
||||
ng-click="controller.bypassSelection($event)">
|
||||
<div class="l-grid l-grid-x"
|
||||
ng-if="!controller.getGridSize()[0] < 3"
|
||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
||||
@ -34,10 +36,12 @@
|
||||
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
||||
</div>
|
||||
|
||||
<div class='abs frame t-frame-outer child-frame panel s-selectable s-moveable s-hover-border'
|
||||
ng-class="{ 'no-frame': !controller.hasFrame(childObject), 's-selected':controller.selected(childObject) }"
|
||||
<div class="abs frame t-frame-outer child-frame panel s-selectable s-moveable s-hover-border {{childObject.getId() + '-' + $id}} t-object-type-{{ childObject.getModel().type }}"
|
||||
ng-class="{ 'no-frame': !controller.hasFrame(childObject), 's-drilled-in': controller.isDrilledIn(childObject) }"
|
||||
ng-repeat="childObject in composition"
|
||||
ng-click="controller.select($event, childObject.getId())"
|
||||
ng-init="controller.selectIfNew(childObject.getId() + '-' + $id, childObject)"
|
||||
mct-selectable="controller.getContext(childObject, true)"
|
||||
ng-dblclick="controller.drill($event, childObject)"
|
||||
ng-style="controller.getFrameStyle(childObject.getId())">
|
||||
|
||||
<mct-representation key="'frame'"
|
||||
@ -45,7 +49,7 @@
|
||||
mct-object="childObject">
|
||||
</mct-representation>
|
||||
<!-- Drag handles -->
|
||||
<span class="abs t-edit-handle-holder s-hover-border" ng-if="controller.selected(childObject)">
|
||||
<span class="abs t-edit-handle-holder" ng-if="controller.selected(childObject) && !controller.isDrilledIn(childObject)">
|
||||
<span class="edit-handle edit-move"
|
||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [0,0])"
|
||||
mct-drag="controller.continueDrag(delta)"
|
||||
@ -73,7 +77,6 @@
|
||||
mct-drag-up="controller.endDrag()">
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
);
|
||||
|
@ -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 = $('<div></div>');
|
||||
$(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 = $("<div class='some-class'></div>");
|
||||
$element.append(testElement);
|
||||
spyOn(testElement[0], 'click');
|
||||
|
||||
controller.selectIfNew('some-class', childObj);
|
||||
jasmine.Clock.tick(0);
|
||||
|
||||
expect(testElement[0].click).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ define([
|
||||
"delegates": [
|
||||
"telemetry"
|
||||
],
|
||||
"inspector": tableInspector,
|
||||
"inspector": "table-options-edit",
|
||||
"contains": [
|
||||
{
|
||||
"has": "telemetry"
|
||||
|
@ -19,7 +19,10 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-controller="TableOptionsController" class="l-controls-first flex-elem grows l-inspector-part">
|
||||
|
||||
<div ng-if="domainObject.getCapability('editor').inEditContext()"
|
||||
ng-controller="TableOptionsController"
|
||||
class="l-controls-first flex-elem grows l-inspector-part">
|
||||
<em class="t-inspector-part-header" title="Display properties for this object">Table Options</em>
|
||||
<mct-form
|
||||
ng-model="configuration.table.columns"
|
||||
|
17
src/MCT.js
17
src/MCT.js
@ -28,7 +28,8 @@ define([
|
||||
'./selection/Selection',
|
||||
'./api/objects/object-utils',
|
||||
'./plugins/plugins',
|
||||
'./ui/ViewRegistry'
|
||||
'./ui/ViewRegistry',
|
||||
'./ui/InspectorViewRegistry'
|
||||
], function (
|
||||
EventEmitter,
|
||||
legacyRegistry,
|
||||
@ -37,7 +38,8 @@ define([
|
||||
Selection,
|
||||
objectUtils,
|
||||
plugins,
|
||||
ViewRegistry
|
||||
ViewRegistry,
|
||||
InspectorViewRegistry
|
||||
) {
|
||||
/**
|
||||
* Open MCT is an extensible web application for building mission
|
||||
@ -112,15 +114,13 @@ define([
|
||||
|
||||
/**
|
||||
* Registry for views which should appear in the Inspector area.
|
||||
* These views will be chosen based on selection state, so
|
||||
* providers should be prepared to test arbitrary objects for
|
||||
* viewability.
|
||||
* These views will be chosen based on the selection state.
|
||||
*
|
||||
* @type {module:openmct.ViewRegistry}
|
||||
* @type {module:openmct.InspectorViewRegistry}
|
||||
* @memberof module:openmct.MCT#
|
||||
* @name inspectors
|
||||
* @name inspectorViews
|
||||
*/
|
||||
this.inspectors = new ViewRegistry();
|
||||
this.inspectorViews = new InspectorViewRegistry();
|
||||
|
||||
/**
|
||||
* Registry for views which should appear in Edit Properties
|
||||
@ -196,7 +196,6 @@ define([
|
||||
|
||||
this.Dialog = api.Dialog;
|
||||
|
||||
this.on('navigation', this.selection.clear.bind(this.selection));
|
||||
}
|
||||
|
||||
MCT.prototype = Object.create(EventEmitter.prototype);
|
||||
|
@ -33,37 +33,96 @@ define(['EventEmitter'], function (EventEmitter) {
|
||||
|
||||
Selection.prototype = Object.create(EventEmitter.prototype);
|
||||
|
||||
Selection.prototype.add = function (context) {
|
||||
this.clear(); // Only allow single select as initial simplification
|
||||
this.selected.push(context);
|
||||
this.emit('change');
|
||||
};
|
||||
|
||||
Selection.prototype.remove = function (path) {
|
||||
this.selected = this.selected.filter(function (otherPath) {
|
||||
return !path.matches(otherPath);
|
||||
});
|
||||
this.emit('change');
|
||||
};
|
||||
|
||||
Selection.prototype.contains = function (path) {
|
||||
return this.selected.some(function (otherPath) {
|
||||
return path.matches(otherPath);
|
||||
});
|
||||
};
|
||||
|
||||
Selection.prototype.clear = function () {
|
||||
this.selected = [];
|
||||
this.emit('change');
|
||||
};
|
||||
|
||||
Selection.prototype.primary = function () {
|
||||
return this.selected[this.selected.length - 1];
|
||||
};
|
||||
|
||||
Selection.prototype.all = function () {
|
||||
/**
|
||||
* Gets the selected object.
|
||||
* @public
|
||||
*/
|
||||
Selection.prototype.get = function () {
|
||||
return this.selected;
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects the selectable object and emits the 'change' event.
|
||||
*
|
||||
* @param {object} selectable an object with element and context properties
|
||||
* @private
|
||||
*/
|
||||
Selection.prototype.select = function (selectable) {
|
||||
if (!Array.isArray(selectable)) {
|
||||
selectable = [selectable];
|
||||
}
|
||||
|
||||
if (this.selected[0] && this.selected[0].element) {
|
||||
this.selected[0].element.classList.remove('s-selected');
|
||||
}
|
||||
|
||||
if (this.selected[1]) {
|
||||
this.selected[1].element.classList.remove('s-selected-parent');
|
||||
}
|
||||
|
||||
if (selectable[0] && selectable[0].element) {
|
||||
selectable[0].element.classList.add('s-selected');
|
||||
}
|
||||
|
||||
if (selectable[1]) {
|
||||
selectable[1].element.classList.add('s-selected-parent');
|
||||
}
|
||||
|
||||
this.selected = selectable;
|
||||
this.emit('change', this.selected);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Selection.prototype.capture = function (selectable) {
|
||||
if (!this.capturing) {
|
||||
this.capturing = [];
|
||||
}
|
||||
|
||||
this.capturing.push(selectable);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Selection.prototype.selectCapture = function (selectable) {
|
||||
if (!this.capturing) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.select(this.capturing.reverse());
|
||||
delete this.capturing;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches the click handlers to the element.
|
||||
*
|
||||
* @param element an html element
|
||||
* @param context object with oldItem, item and toolbar properties
|
||||
* @param select a flag to select the element if true
|
||||
* @returns a function that removes the click handlers from the element
|
||||
* @public
|
||||
*/
|
||||
Selection.prototype.selectable = function (element, context, select) {
|
||||
var selectable = {
|
||||
context: context,
|
||||
element: element
|
||||
};
|
||||
var capture = this.capture.bind(this, selectable);
|
||||
var selectCapture = this.selectCapture.bind(this, selectable);
|
||||
element.addEventListener('click', capture, true);
|
||||
element.addEventListener('click', selectCapture);
|
||||
|
||||
if (select) {
|
||||
this.select(selectable);
|
||||
}
|
||||
|
||||
return function () {
|
||||
element.removeEventListener('click', capture);
|
||||
element.removeEventListener('click', selectCapture);
|
||||
};
|
||||
};
|
||||
|
||||
return Selection;
|
||||
});
|
||||
|
154
src/ui/InspectorViewRegistry.js
Normal file
154
src/ui/InspectorViewRegistry.js
Normal file
@ -0,0 +1,154 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
/*global console */
|
||||
|
||||
define([], function () {
|
||||
|
||||
/**
|
||||
* A InspectorViewRegistry maintains the definitions for views
|
||||
* that may occur in the inspector.
|
||||
*
|
||||
* @interface InspectorViewRegistry
|
||||
* @memberof module:openmct
|
||||
*/
|
||||
function InspectorViewRegistry() {
|
||||
this.providers = {};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} selection the object to be viewed
|
||||
* @returns {module:openmct.InspectorViewRegistry[]} any providers
|
||||
* which can provide views of this object
|
||||
* @private for platform-internal use
|
||||
*/
|
||||
InspectorViewRegistry.prototype.get = function (selection) {
|
||||
var providers = this.getAllProviders().filter(function (provider) {
|
||||
return provider.canView(selection);
|
||||
});
|
||||
|
||||
if (providers && providers.length > 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;
|
||||
});
|
Loading…
Reference in New Issue
Block a user