mirror of
https://github.com/nasa/openmct.git
synced 2025-06-05 09:00:49 +00:00
[Plots] #638 added onchange handling in order to synchronize forms with domain object model.
Fixed failing test Added tests jslint errors Minor refactoring of layout bundle revert layout/bundle.json
This commit is contained in:
parent
f2903f4030
commit
abf5f22155
@ -295,7 +295,7 @@ define([
|
|||||||
"provides": "typeService",
|
"provides": "typeService",
|
||||||
"type": "decorator",
|
"type": "decorator",
|
||||||
"implementation": TypeRegionDecorator
|
"implementation": TypeRegionDecorator
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
"runs": [
|
"runs": [
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ define(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.addPart(metadataPart, 0);
|
this.addPart(metadataPart, 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
return InspectorRegion;
|
return InspectorRegion;
|
||||||
}
|
}
|
||||||
|
@ -29,16 +29,17 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds default screen regions to Type definitions. Screen regions
|
* Adds default browse screen regions to Type definitions. Screen
|
||||||
* are sections of the browse and edit view of an object that can be
|
* regions are sections of the browse and edit view of an object
|
||||||
* customized on a per-type basis. Within {@link Region}s are {@link RegionPart}s.
|
* that can be customized on a per-type basis. Within
|
||||||
* Policies can be used to decide which parts are visible or not based on object state.
|
* {@link Region}s are {@link RegionPart}s. Policies can be used to
|
||||||
|
* decide which parts are visible or not based on object state.
|
||||||
* @memberOf platform/commonUI/regions
|
* @memberOf platform/commonUI/regions
|
||||||
* @see {@link Region}, {@link RegionPart}, {@link EditableRegionPolicy}
|
* @see {@link Region}, {@link RegionPart}, {@link EditableRegionPolicy}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function TypeRegionDecorator(typeService) {
|
function TypeRegionDecorator(typeService) {
|
||||||
this.typeService = typeService
|
this.typeService = typeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,11 +33,11 @@ define(
|
|||||||
var inspectorRegion;
|
var inspectorRegion;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
inspectorRegion = new InspectorRegion;
|
inspectorRegion = new InspectorRegion();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates default region parts", function () {
|
it("creates default region parts", function () {
|
||||||
expect(inspectorRegion.parts().length).toBe(2);
|
expect(inspectorRegion.parts.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
70
platform/commonUI/browse/test/TypeRegionDecoratorSpec.js
Normal file
70
platform/commonUI/browse/test/TypeRegionDecoratorSpec.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MCTIncudeSpec. Created by vwoeltje on 11/6/14.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
["../src/TypeRegionDecorator"],
|
||||||
|
function (TypeRegionDecorator) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The type region decorator", function () {
|
||||||
|
var typeRegionDecorator,
|
||||||
|
mockTypeService,
|
||||||
|
mockType,
|
||||||
|
mockTypeDefinition;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTypeDefinition = {};
|
||||||
|
|
||||||
|
mockType = jasmine.createSpyObj('type', [
|
||||||
|
'getDefinition'
|
||||||
|
]);
|
||||||
|
mockType.getDefinition.andReturn(mockTypeDefinition);
|
||||||
|
|
||||||
|
mockTypeService = jasmine.createSpyObj('typeService', [
|
||||||
|
'listTypes',
|
||||||
|
'getType'
|
||||||
|
]);
|
||||||
|
mockTypeService.getType.andReturn(mockType);
|
||||||
|
mockTypeService.listTypes.andReturn([mockType]);
|
||||||
|
|
||||||
|
typeRegionDecorator = new TypeRegionDecorator(mockTypeService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("decorates individual type definitions with basic inspector" +
|
||||||
|
" region", function () {
|
||||||
|
typeRegionDecorator.getType('someType');
|
||||||
|
expect(mockTypeDefinition.regions).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("decorates all type definitions with basic inspector" +
|
||||||
|
" region", function () {
|
||||||
|
typeRegionDecorator.listTypes();
|
||||||
|
expect(mockTypeDefinition.regions).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -23,6 +23,7 @@
|
|||||||
ng-controller="DateTimeFieldController">
|
ng-controller="DateTimeFieldController">
|
||||||
<input type="text"
|
<input type="text"
|
||||||
ng-model="textValue"
|
ng-model="textValue"
|
||||||
|
ng-change="structure.onchange(ngModel[field])"
|
||||||
ng-blur="restoreTextValue(); ngBlur()"
|
ng-blur="restoreTextValue(); ngBlur()"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
error: textInvalid ||
|
error: textInvalid ||
|
||||||
|
@ -44,11 +44,11 @@ define(
|
|||||||
if (domainObject.getCapability('status').get('editing')){
|
if (domainObject.getCapability('status').get('editing')){
|
||||||
//If the domain object is in edit mode, only include a part
|
//If the domain object is in edit mode, only include a part
|
||||||
// if it is marked editable
|
// if it is marked editable
|
||||||
return regionPart.modes.indexOf('edit') != -1;
|
return regionPart.modes.indexOf('edit') !== -1;
|
||||||
} else {
|
} else {
|
||||||
//If the domain object is not in edit mode, return any parts
|
//If the domain object is not in edit mode, return any parts
|
||||||
// that are not explicitly marked editable
|
// that are not explicitly marked editable
|
||||||
return regionPart.modes.indexOf('browse') != -1;
|
return regionPart.modes.indexOf('browse') !== -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,17 +74,19 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a part from this region.
|
* Removes a part from this region.
|
||||||
* @param {RegionPart} part the part to add
|
* @param {RegionPart | number | strnig} part The region part to
|
||||||
* @param {number} [index] the position to insert the part. By default
|
* remove. If a number, will remove the part at that index. If a
|
||||||
* will add to the end
|
* string, will remove the part with the matching name. If an
|
||||||
|
* object, will attempt to remove that object from the Region
|
||||||
*/
|
*/
|
||||||
Region.prototype.removePart = function (part){
|
Region.prototype.removePart = function (part){
|
||||||
if (typeof part === 'number') {
|
if (typeof part === 'number') {
|
||||||
this.parts.splice(part, 1);
|
this.parts.splice(part, 1);
|
||||||
} else if (typeof part === 'string'){
|
} else if (typeof part === 'string'){
|
||||||
this.parts
|
this.parts = this.parts.filter(function(thisPart) {
|
||||||
}
|
return thisPart.name !== part;
|
||||||
else {
|
});
|
||||||
|
} else {
|
||||||
this.parts.splice(this.parts.indexOf(part), 1);
|
this.parts.splice(this.parts.indexOf(part), 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -37,22 +37,19 @@ define(
|
|||||||
typeCapability = domainObject.getCapability('type');
|
typeCapability = domainObject.getCapability('type');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Refactor this out, probably to a directive.
|
* Filters region parts to only those allowed by region policies
|
||||||
* Or, alternatively, could have a regionCapability that returns
|
|
||||||
* regions and parts filtered for applicability to current
|
|
||||||
* object state.
|
|
||||||
* @param regions
|
* @param regions
|
||||||
* @returns {*}
|
* @returns {{}}
|
||||||
*/
|
*/
|
||||||
function filterParts(regions) {
|
function filterParts(regions) {
|
||||||
//Dupe so we're not modifying the type definition.
|
//Dupe so we're not modifying the type definition.
|
||||||
var filteredRegions = {};
|
var filteredRegions = {};
|
||||||
for (var regionName in regions) {
|
Object.keys(regions).forEach(function(regionName) {
|
||||||
filteredRegions[regionName] = Object.create(regions[regionName]);
|
filteredRegions[regionName] = Object.create(regions[regionName]);
|
||||||
filteredRegions[regionName].parts = regions[regionName].parts.filter(function(part){
|
filteredRegions[regionName].parts = (regions[regionName].parts || []).filter(function(part){
|
||||||
return policyService.allow('region', part, domainObject);
|
return policyService.allow('region', part, domainObject);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
return filteredRegions;
|
return filteredRegions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
75
platform/commonUI/regions/test/EditableRegionPolicySpec.js
Normal file
75
platform/commonUI/regions/test/EditableRegionPolicySpec.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,describe,it,expect,beforeEach,waitsFor,jasmine */
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../src/EditableRegionPolicy'],
|
||||||
|
function (EditableRegionPolicy) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The editable region policy ", function () {
|
||||||
|
|
||||||
|
var editableRegionPolicy,
|
||||||
|
mockDomainObject,
|
||||||
|
mockStatusCapability,
|
||||||
|
mockBrowseRegionPart = {
|
||||||
|
modes: 'browse'
|
||||||
|
},
|
||||||
|
mockEditRegionPart = {
|
||||||
|
modes: 'edit'
|
||||||
|
},
|
||||||
|
mockAllModesRegionPart = {};
|
||||||
|
|
||||||
|
beforeEach(function(){
|
||||||
|
editableRegionPolicy = new EditableRegionPolicy();
|
||||||
|
|
||||||
|
mockStatusCapability = jasmine.createSpyObj("statusCapability", [
|
||||||
|
"get"
|
||||||
|
]);
|
||||||
|
mockDomainObject = jasmine.createSpyObj("domainObject", [
|
||||||
|
"getCapability"
|
||||||
|
]);
|
||||||
|
mockDomainObject.getCapability.andReturn(mockStatusCapability);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes only browse region parts for object not in edit mode", function() {
|
||||||
|
mockStatusCapability.get.andReturn(false);
|
||||||
|
expect(editableRegionPolicy.allow(mockBrowseRegionPart, mockDomainObject)).toBe(true);
|
||||||
|
expect(editableRegionPolicy.allow(mockEditRegionPart, mockDomainObject)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes only edit region parts for object in edit mode", function() {
|
||||||
|
mockStatusCapability.get.andReturn(true);
|
||||||
|
expect(editableRegionPolicy.allow(mockBrowseRegionPart, mockDomainObject)).toBe(false);
|
||||||
|
expect(editableRegionPolicy.allow(mockEditRegionPart, mockDomainObject)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes region parts with no mode specification", function() {
|
||||||
|
mockStatusCapability.get.andReturn(false);
|
||||||
|
expect(editableRegionPolicy.allow(mockAllModesRegionPart, mockDomainObject)).toBe(true);
|
||||||
|
mockStatusCapability.get.andReturn(true);
|
||||||
|
expect(editableRegionPolicy.allow(mockAllModesRegionPart, mockDomainObject)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
82
platform/commonUI/regions/test/RegionControllerSpec.js
Normal file
82
platform/commonUI/regions/test/RegionControllerSpec.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,describe,it,expect,beforeEach,waitsFor,jasmine */
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../src/RegionController'],
|
||||||
|
function (RegionController) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The region controller ", function () {
|
||||||
|
var mockScope,
|
||||||
|
mockDomainObject,
|
||||||
|
mockTypeCapability,
|
||||||
|
mockTypeDefinition,
|
||||||
|
mockPolicyService,
|
||||||
|
controller;
|
||||||
|
|
||||||
|
beforeEach(function(){
|
||||||
|
mockTypeDefinition = {
|
||||||
|
regions:
|
||||||
|
{
|
||||||
|
'regionOne': {
|
||||||
|
'parts': [
|
||||||
|
{'name': 'Part One'},
|
||||||
|
{'name': 'Part Two'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mockTypeCapability = jasmine.createSpyObj('typeCapability', [
|
||||||
|
'getDefinition'
|
||||||
|
]);
|
||||||
|
mockTypeCapability.getDefinition.andReturn(mockTypeDefinition);
|
||||||
|
|
||||||
|
mockDomainObject = jasmine.createSpyObj('domainObject', [
|
||||||
|
'getCapability'
|
||||||
|
]);
|
||||||
|
mockDomainObject.getCapability.andReturn(mockTypeCapability);
|
||||||
|
|
||||||
|
mockPolicyService = jasmine.createSpyObj('policyService', [
|
||||||
|
'allow'
|
||||||
|
]);
|
||||||
|
|
||||||
|
mockScope = {
|
||||||
|
domainObject: mockDomainObject
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters out regions disallowed by region policy", function() {
|
||||||
|
mockPolicyService.allow.andReturn(false);
|
||||||
|
controller = new RegionController(mockScope, mockPolicyService);
|
||||||
|
expect(mockScope.regions.regionOne.parts.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not filter out regions allowed by region policy", function() {
|
||||||
|
mockPolicyService.allow.andReturn(true);
|
||||||
|
controller = new RegionController(mockScope, mockPolicyService);
|
||||||
|
expect(mockScope.regions.regionOne.parts.length).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
107
platform/commonUI/regions/test/RegionSpec.js
Normal file
107
platform/commonUI/regions/test/RegionSpec.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,describe,it,expect,beforeEach,waitsFor,jasmine */
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../src/Region'],
|
||||||
|
function (Region) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The region class ", function () {
|
||||||
|
|
||||||
|
var region,
|
||||||
|
part2 = {'name': 'part2'};
|
||||||
|
|
||||||
|
beforeEach(function(){
|
||||||
|
region = new Region();
|
||||||
|
region.parts = [
|
||||||
|
{name: 'part1'},
|
||||||
|
{name: 'part3'},
|
||||||
|
{name: 'part4'}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adding a region part at a specified index adds it in that" +
|
||||||
|
" position", function() {
|
||||||
|
|
||||||
|
region.addPart(part2, 1);
|
||||||
|
|
||||||
|
expect(region.parts.length).toBe(4);
|
||||||
|
expect(region.parts[1]).toBe(part2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adding a region part without an index adds it at the end", function() {
|
||||||
|
var partN = {'name': 'partN'};
|
||||||
|
|
||||||
|
region.addPart(partN);
|
||||||
|
|
||||||
|
expect(region.parts.length).toBe(4);
|
||||||
|
expect(region.parts[region.parts.length-1]).toBe(partN);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("removing a region part", function(){
|
||||||
|
var partName = "part2";
|
||||||
|
|
||||||
|
beforeEach(function(){
|
||||||
|
region.parts = [
|
||||||
|
{name: 'part1'},
|
||||||
|
part2,
|
||||||
|
{name: 'part3'},
|
||||||
|
{name: 'part4'}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
it("with a string matches on region part" +
|
||||||
|
" name", function() {
|
||||||
|
expect(region.parts.length).toBe(4);
|
||||||
|
expect(region.parts.indexOf(part2)).toBe(1);
|
||||||
|
|
||||||
|
region.removePart(partName);
|
||||||
|
|
||||||
|
expect(region.parts.length).toBe(3);
|
||||||
|
expect(region.parts.indexOf(part2)).toBe(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("with a number removes by index", function() {
|
||||||
|
expect(region.parts.length).toBe(4);
|
||||||
|
expect(region.parts.indexOf(part2)).toBe(1);
|
||||||
|
|
||||||
|
region.removePart(1);
|
||||||
|
|
||||||
|
expect(region.parts.length).toBe(3);
|
||||||
|
expect(region.parts.indexOf(part2)).toBe(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("with object matches that object", function() {
|
||||||
|
expect(region.parts.length).toBe(4);
|
||||||
|
expect(region.parts.indexOf(part2)).toBe(1);
|
||||||
|
|
||||||
|
region.removePart(part2);
|
||||||
|
|
||||||
|
expect(region.parts.length).toBe(3);
|
||||||
|
expect(region.parts.indexOf(part2)).toBe(-1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -1,3 +0,0 @@
|
|||||||
[
|
|
||||||
"InspectorRegion"
|
|
||||||
]
|
|
@ -25,45 +25,15 @@ define([
|
|||||||
"./src/LayoutController",
|
"./src/LayoutController",
|
||||||
"./src/FixedController",
|
"./src/FixedController",
|
||||||
"./src/LayoutCompositionPolicy",
|
"./src/LayoutCompositionPolicy",
|
||||||
"../../commonUI/browse/src/InspectorRegion",
|
|
||||||
"./src/PlotOptionsController",
|
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
LayoutController,
|
LayoutController,
|
||||||
FixedController,
|
FixedController,
|
||||||
LayoutCompositionPolicy,
|
LayoutCompositionPolicy,
|
||||||
InspectorRegion,
|
|
||||||
PlotOptionsController,
|
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
|
||||||
* Customize and extend the default 'Inspector' region for the panel
|
|
||||||
* type, to add display options for plots. This should be moved to a
|
|
||||||
* dedicated type.
|
|
||||||
* @type {InspectorRegion}
|
|
||||||
*/
|
|
||||||
var plotInspector = new InspectorRegion(),
|
|
||||||
plotOptionsBrowsePart = {
|
|
||||||
name: "plot-options",
|
|
||||||
title: "Plot Options",
|
|
||||||
modes: ['browse'],
|
|
||||||
content: {
|
|
||||||
key: "plot-options-browse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plotOptionsEditPart = {
|
|
||||||
name: "plot-options",
|
|
||||||
title: "Plot Options",
|
|
||||||
modes: ['edit'],
|
|
||||||
content: {
|
|
||||||
key: "plot-options-browse"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
plotInspector.addPart(plotOptionsBrowsePart);
|
|
||||||
plotInspector.addPart(plotOptionsEditPart);
|
|
||||||
|
|
||||||
legacyRegistry.register("platform/features/layout", {
|
legacyRegistry.register("platform/features/layout", {
|
||||||
"name": "Layout components.",
|
"name": "Layout components.",
|
||||||
"description": "Plug in adding Layout capabilities.",
|
"description": "Plug in adding Layout capabilities.",
|
||||||
@ -222,10 +192,6 @@ define([
|
|||||||
{
|
{
|
||||||
"key": "frame",
|
"key": "frame",
|
||||||
"templateUrl": "templates/frame.html"
|
"templateUrl": "templates/frame.html"
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "plot-options-browse",
|
|
||||||
"templateUrl": "templates/plot-options-browse.html"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"controllers": [
|
"controllers": [
|
||||||
@ -247,13 +213,6 @@ define([
|
|||||||
"telemetryFormatter",
|
"telemetryFormatter",
|
||||||
"throttle"
|
"throttle"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "PlotOptionsController",
|
|
||||||
"implementation": PlotOptionsController,
|
|
||||||
"depends": [
|
|
||||||
"$scope"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"templates": [
|
"templates": [
|
||||||
@ -353,12 +312,7 @@ define([
|
|||||||
"property": "layoutGrid",
|
"property": "layoutGrid",
|
||||||
"conversion": "number[]"
|
"conversion": "number[]"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"regions": {
|
|
||||||
"inspector": plotInspector
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,31 @@
|
|||||||
this source code distribution or the Licensing information page available
|
this source code distribution or the Licensing information page available
|
||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
|
<style>
|
||||||
|
.l-inspect .l-inspector-part .no-margin .form {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.reduced-min-width .form .form-row > .label {
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<div ng-controller="PlotOptionsController" class="flex-elem grows l-inspector-part">
|
<div ng-controller="PlotOptionsController" class="flex-elem grows l-inspector-part">
|
||||||
<em class="t-inspector-part-header" title="Display properties for this object">Display</em>
|
<em class="t-inspector-part-header" title="Display properties for this object">Display</em>
|
||||||
|
<mct-form
|
||||||
|
ng-model="configuration.plot.xAxis"
|
||||||
|
structure="xAxisForm"
|
||||||
|
name="xAxisFormState"
|
||||||
|
class="flex-elem l-flex-row no-validate no-margin reduced-min-width">
|
||||||
|
</mct-form>
|
||||||
|
<mct-form
|
||||||
|
ng-model="configuration.plot.yAxis"
|
||||||
|
structure="yAxisForm"
|
||||||
|
name="yAxisFormState"
|
||||||
|
class="flex-elem l-flex-row no-validate no-margin reduced-min-width">
|
||||||
|
</mct-form>
|
||||||
|
<div class="section-header ng-binding ng-scope">
|
||||||
|
Plot Series
|
||||||
|
</div>
|
||||||
<ul class="first flex-elem grows vscroll">
|
<ul class="first flex-elem grows vscroll">
|
||||||
<ul class="tree">
|
<ul class="tree">
|
||||||
<li ng-repeat="child in children">
|
<li ng-repeat="child in children">
|
||||||
@ -41,8 +64,8 @@
|
|||||||
</span>
|
</span>
|
||||||
<mct-form
|
<mct-form
|
||||||
ng-class="{hidden: !toggle.isActive()}"
|
ng-class="{hidden: !toggle.isActive()}"
|
||||||
ng-model="plotOptionsModel"
|
ng-model="configuration.plot.series[child.getId()]"
|
||||||
structure="plotOptionsStructure"
|
structure="plotSeriesForm"
|
||||||
name="plotOptionsState"
|
name="plotOptionsState"
|
||||||
class="flex-elem l-flex-row l-controls-first no-validate">
|
class="flex-elem l-flex-row l-controls-first no-validate">
|
||||||
</mct-form>
|
</mct-form>
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
* @namespace platform/features/layout
|
* @namespace platform/features/layout
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
[],
|
['./PlotOptionsForm'],
|
||||||
function () {
|
function (PlotOptionsForm) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,136 +50,98 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @param {Scope} $scope the controller's Angular scope
|
* @param {Scope} $scope the controller's Angular scope
|
||||||
*/
|
*/
|
||||||
function PlotOptionsController($scope) {
|
function PlotOptionsController($scope, topic) {
|
||||||
|
|
||||||
var self = this,
|
var self = this,
|
||||||
domainObject = $scope.domainObject,
|
domainObject = $scope.domainObject,
|
||||||
xAxisForm = {
|
composition,
|
||||||
'name':'x-axis',
|
mutationListener,
|
||||||
'sections': [{
|
formListener,
|
||||||
'name': 'x-axis',
|
configuration = domainObject.getModel().configuration || {};
|
||||||
'rows': [
|
|
||||||
{
|
|
||||||
'name': 'Domain',
|
|
||||||
'control': 'select',
|
|
||||||
'key': 'key',
|
|
||||||
//TODO fetch options from platform or object type configuration
|
|
||||||
'options': [
|
|
||||||
{'name':'scet', 'value': 'scet'},
|
|
||||||
{'name':'sclk', 'value': 'sclk'},
|
|
||||||
{'name':'lst', 'value': 'lst'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}]},
|
|
||||||
yAxisForm = {
|
|
||||||
'name':'y-axis',
|
|
||||||
'sections': [{
|
|
||||||
// Will need to be repeated for each y-axis, with a
|
|
||||||
// distinct name each. Ideally the name of the axis itself.
|
|
||||||
'name': 'y-axis',
|
|
||||||
'rows': [
|
|
||||||
{
|
|
||||||
'name': 'Autoscale',
|
|
||||||
'control': 'checkbox',
|
|
||||||
'key': 'autoscale',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Min',
|
|
||||||
'control': 'textfield',
|
|
||||||
'key': 'min',
|
|
||||||
'pattern': '[0-9]'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Max',
|
|
||||||
'control': 'textfield',
|
|
||||||
'key': 'min',
|
|
||||||
'pattern': '[0-9]'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Range',
|
|
||||||
'control': 'select',
|
|
||||||
'key': 'key',
|
|
||||||
'options': [
|
|
||||||
{'name':'eu', 'value': 'eu'},
|
|
||||||
{'name':'dn', 'value': 'dn'},
|
|
||||||
{'name':'status', 'value': 'status'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
plotSeriesForm = {
|
|
||||||
// For correctness of the rendered markup, repeated forms
|
|
||||||
// will probably need to have unique names.
|
|
||||||
'name': 'plotSeries',
|
|
||||||
'sections': [{
|
|
||||||
'name': 'Plot Series',
|
|
||||||
'rows': [
|
|
||||||
{
|
|
||||||
'name': 'Markers',
|
|
||||||
'control': 'checkbox',
|
|
||||||
'key': 'markers'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'No Line',
|
|
||||||
'control': 'radio',
|
|
||||||
'key': 'noLine'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Step Line',
|
|
||||||
'control': 'radio',
|
|
||||||
'key': 'stepLine'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'Linear Line',
|
|
||||||
'control': 'radio',
|
|
||||||
'key': 'linearLine'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
plotOptionsModel = {};
|
|
||||||
|
|
||||||
/*domainObject.getModel().configuration.plot.xAxis= {
|
this.plotOptionsForm = new PlotOptionsForm(topic);
|
||||||
'key': 'scet'
|
|
||||||
};
|
|
||||||
|
|
||||||
domainObject.getModel().configuration.plot.yAxis = [{
|
/*
|
||||||
'autoscale': true,
|
* Determine whether the changes to the model that triggered a
|
||||||
'min': 0,
|
* mutation event were purely compositional.
|
||||||
'max': 15,
|
*/
|
||||||
'key': 'eu'
|
function hasCompositionChanged(oldComposition, newComposition){
|
||||||
}];
|
// Framed slightly strangely, but the boolean logic is
|
||||||
|
// easier to follow for the unchanged case.
|
||||||
|
var isUnchanged = oldComposition === newComposition ||
|
||||||
|
(
|
||||||
|
oldComposition.length === newComposition.length &&
|
||||||
|
oldComposition.every( function (currentValue, index) {
|
||||||
|
return newComposition[index] && currentValue === newComposition[index];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return !isUnchanged;
|
||||||
|
}
|
||||||
|
|
||||||
domainObject.getModel().configuration.plot.series = [
|
/*
|
||||||
{
|
Default the plot options model
|
||||||
'id': '',
|
*/
|
||||||
'lineStyle': '',
|
function defaultConfiguration() {
|
||||||
'color': '#aaddaa',
|
configuration.plot = configuration.plot || {};
|
||||||
'interpolation': 'none'
|
configuration.plot.xAxis = configuration.plot.xAxis || {};
|
||||||
},
|
configuration.plot.yAxis = configuration.plot.yAxis || {}; // y-axes will be associative array keyed on axis key
|
||||||
//etc
|
configuration.plot.series = configuration.plot.series || {}; // series will be associative array keyed on sub-object id
|
||||||
];*/
|
$scope.configuration = configuration;
|
||||||
|
}
|
||||||
$scope.plotOptionsStructure = plotSeriesForm;
|
|
||||||
$scope.plotOptionsModel = plotOptionsModel;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
When a child is added to, or removed from a plot, update the
|
||||||
|
plot options model
|
||||||
|
*/
|
||||||
function updateChildren() {
|
function updateChildren() {
|
||||||
domainObject.useCapability('composition').then(function(children){
|
domainObject.useCapability('composition').then(function(children){
|
||||||
$scope.children = children;
|
$scope.children = children;
|
||||||
|
composition = domainObject.getModel().composition;
|
||||||
|
children.forEach(function(child){
|
||||||
|
configuration.plot.series[child.getId()] = configuration.plot.series[child.getId()] || {};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
On changes to the form, update the configuration on the domain
|
||||||
|
object
|
||||||
|
*/
|
||||||
|
function updateConfiguration() {
|
||||||
|
domainObject.useCapability('mutation', function(model){
|
||||||
|
model.configuration = model.configuration || {};
|
||||||
|
model.configuration.plot = configuration.plot;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set form structures on scope
|
||||||
|
*/
|
||||||
|
$scope.plotSeriesForm = this.plotOptionsForm.plotSeriesForm;
|
||||||
|
$scope.xAxisForm = this.plotOptionsForm.xAxisForm;
|
||||||
|
$scope.yAxisForm = this.plotOptionsForm.yAxisForm;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Listen for changes to the domain object and update the object's
|
Listen for changes to the domain object and update the object's
|
||||||
children.
|
children.
|
||||||
*/
|
*/
|
||||||
domainObject.getCapability('mutation').listen(function(model) {
|
mutationListener = domainObject.getCapability('mutation').listen(function(model) {
|
||||||
updateChildren();
|
if (hasCompositionChanged(composition, model.composition)) {
|
||||||
|
updateChildren();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
formListener = this.plotOptionsForm.listen(updateConfiguration);
|
||||||
|
|
||||||
|
defaultConfiguration();
|
||||||
updateChildren();
|
updateChildren();
|
||||||
|
|
||||||
|
$scope.$on("$destroy", function() {
|
||||||
|
//Clean up any listeners on destruction of controller
|
||||||
|
mutationListener();
|
||||||
|
formListener();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PlotOptionsController;
|
return PlotOptionsController;
|
||||||
|
166
platform/features/layout/src/PlotOptionsForm.js
Normal file
166
platform/features/layout/src/PlotOptionsForm.js
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for encapsulating structure and behaviour of the plot
|
||||||
|
* options form
|
||||||
|
* @memberOf platform/features/layout
|
||||||
|
* @param topic
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function PlotOptionsForm(topic) {
|
||||||
|
var self = this;
|
||||||
|
this.onchangeTopic = topic();
|
||||||
|
|
||||||
|
function onchange(value){
|
||||||
|
self.onchangeTopic.notify(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Defined below are the form structures for the plot options.
|
||||||
|
*/
|
||||||
|
this.xAxisForm = {
|
||||||
|
'name':'x-axis',
|
||||||
|
'sections': [{
|
||||||
|
'name': 'x-axis',
|
||||||
|
'rows': [
|
||||||
|
{
|
||||||
|
'name': 'Domain',
|
||||||
|
'control': 'select',
|
||||||
|
'key': 'key',
|
||||||
|
'onchange': onchange,
|
||||||
|
'options': [
|
||||||
|
{'name':'scet', 'value': 'scet'},
|
||||||
|
{'name':'sclk', 'value': 'sclk'},
|
||||||
|
{'name':'lst', 'value': 'lst'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]};
|
||||||
|
|
||||||
|
this.yAxisForm = {
|
||||||
|
'name':'y-axis',
|
||||||
|
'sections': [{
|
||||||
|
// Will need to be repeated for each y-axis, with a
|
||||||
|
// distinct name for each. Ideally the name of the axis
|
||||||
|
// itself.
|
||||||
|
'name': 'y-axis',
|
||||||
|
'rows': [
|
||||||
|
{
|
||||||
|
'name': 'Autoscale',
|
||||||
|
'control': 'checkbox',
|
||||||
|
'key': 'autoscale',
|
||||||
|
'onchange': onchange
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Min',
|
||||||
|
'control': 'textfield',
|
||||||
|
'key': 'min',
|
||||||
|
'pattern': '[0-9]',
|
||||||
|
'onchange': onchange
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Max',
|
||||||
|
'control': 'textfield',
|
||||||
|
'key': 'max',
|
||||||
|
'pattern': '[0-9]',
|
||||||
|
'onchange': onchange
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Range',
|
||||||
|
'control': 'select',
|
||||||
|
'key': 'key',
|
||||||
|
'onchange': onchange,
|
||||||
|
'options': [
|
||||||
|
{'name':'eu', 'value': 'eu'},
|
||||||
|
{'name':'dn', 'value': 'dn'},
|
||||||
|
{'name':'status', 'value': 'status'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
this.plotSeriesForm = {
|
||||||
|
'name':'Series Options',
|
||||||
|
'sections': [
|
||||||
|
{
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
'name': 'Color',
|
||||||
|
'control': 'color',
|
||||||
|
'key': 'color',
|
||||||
|
'onchange': onchange
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'rows':[
|
||||||
|
{
|
||||||
|
'name': 'Markers',
|
||||||
|
'control': 'checkbox',
|
||||||
|
'key': 'markers',
|
||||||
|
'onchange': onchange
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'rows':[
|
||||||
|
{
|
||||||
|
'name': 'No Line',
|
||||||
|
'control': 'radio',
|
||||||
|
'key': 'lineType',
|
||||||
|
'value': 'noLine',
|
||||||
|
'onchange': onchange
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Step Line',
|
||||||
|
'control': 'radio',
|
||||||
|
'key': 'lineType',
|
||||||
|
'value': 'stepLine',
|
||||||
|
'onchange': onchange
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Linear Line',
|
||||||
|
'control': 'radio',
|
||||||
|
'key': 'lineType',
|
||||||
|
'value': 'linearLine',
|
||||||
|
'onchange': onchange
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
PlotOptionsForm.prototype.listen = function (callback){
|
||||||
|
return this.onchangeTopic.listen(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
return PlotOptionsForm;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
161
platform/features/layout/test/PlotOptionsControllerSpec.js
Normal file
161
platform/features/layout/test/PlotOptionsControllerSpec.js
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,describe,it,expect,beforeEach,jasmine,xit*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../src/PlotOptionsController'],
|
||||||
|
function (PlotOptionsController) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The Plot Options controller", function () {
|
||||||
|
var plotOptionsController,
|
||||||
|
mockTopicFunction,
|
||||||
|
mockTopicObject,
|
||||||
|
mockDomainObject,
|
||||||
|
mockMutationCapability,
|
||||||
|
mockUseCapabilities,
|
||||||
|
mockCompositionCapability,
|
||||||
|
mockComposition,
|
||||||
|
mockUnlisten,
|
||||||
|
mockFormUnlisten,
|
||||||
|
mockChildOne,
|
||||||
|
mockChildTwo,
|
||||||
|
model,
|
||||||
|
mockScope;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
model = {
|
||||||
|
composition: ['childOne']
|
||||||
|
};
|
||||||
|
|
||||||
|
mockChildOne = jasmine.createSpyObj('domainObject', [
|
||||||
|
'getId'
|
||||||
|
]);
|
||||||
|
mockChildOne.getId.andReturn('childOne');
|
||||||
|
|
||||||
|
mockChildTwo = jasmine.createSpyObj('childTwo', [
|
||||||
|
'getId'
|
||||||
|
]);
|
||||||
|
mockChildOne.getId.andReturn('childTwo');
|
||||||
|
|
||||||
|
mockCompositionCapability = jasmine.createSpyObj('compositionCapability', [
|
||||||
|
'then'
|
||||||
|
]);
|
||||||
|
mockComposition = [
|
||||||
|
mockChildOne
|
||||||
|
];
|
||||||
|
mockCompositionCapability.then.andCallFake(function (callback){
|
||||||
|
callback(mockComposition);
|
||||||
|
});
|
||||||
|
|
||||||
|
mockUseCapabilities = jasmine.createSpyObj('useCapabilities', [
|
||||||
|
'composition',
|
||||||
|
'mutation'
|
||||||
|
]);
|
||||||
|
mockUseCapabilities.composition.andReturn(mockCompositionCapability);
|
||||||
|
|
||||||
|
mockMutationCapability = jasmine.createSpyObj('mutationCapability', [
|
||||||
|
'listen'
|
||||||
|
]);
|
||||||
|
mockUnlisten = jasmine.createSpy('unlisten');
|
||||||
|
mockMutationCapability.listen.andReturn(mockUnlisten);
|
||||||
|
|
||||||
|
|
||||||
|
mockTopicObject = jasmine.createSpyObj('Topic', [
|
||||||
|
'listen',
|
||||||
|
'notify'
|
||||||
|
]);
|
||||||
|
mockFormUnlisten = jasmine.createSpy('formUnlisten');
|
||||||
|
mockTopicObject.listen.andReturn(mockFormUnlisten);
|
||||||
|
|
||||||
|
mockTopicFunction = function() {
|
||||||
|
return mockTopicObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
mockDomainObject = jasmine.createSpyObj('domainObject', [
|
||||||
|
'getModel',
|
||||||
|
'useCapability',
|
||||||
|
'getCapability'
|
||||||
|
]);
|
||||||
|
mockDomainObject.useCapability.andCallFake(function(capability){
|
||||||
|
return mockUseCapabilities[capability]();
|
||||||
|
});
|
||||||
|
mockDomainObject.getCapability.andReturn(mockMutationCapability);
|
||||||
|
mockDomainObject.getModel.andReturn(model);
|
||||||
|
|
||||||
|
mockScope = jasmine.createSpyObj('scope', [
|
||||||
|
'$on'
|
||||||
|
]);
|
||||||
|
mockScope.domainObject = mockDomainObject;
|
||||||
|
|
||||||
|
plotOptionsController = new PlotOptionsController(mockScope, mockTopicFunction);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets form definitions on scope", function () {
|
||||||
|
expect(mockScope.xAxisForm).toBeDefined();
|
||||||
|
expect(mockScope.yAxisForm).toBeDefined();
|
||||||
|
expect(mockScope.plotSeriesForm).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets object children on scope", function () {
|
||||||
|
expect(mockScope.children).toBe(mockComposition);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("on changes in object composition, updates the form", function () {
|
||||||
|
expect(mockMutationCapability.listen).toHaveBeenCalled();
|
||||||
|
expect(mockScope.children).toBe(mockComposition);
|
||||||
|
expect(mockScope.children.length).toBe(1);
|
||||||
|
mockComposition.push(mockChildTwo);
|
||||||
|
model.composition.push('childTwo');
|
||||||
|
mockMutationCapability.listen.mostRecentCall.args[0](model);
|
||||||
|
expect(mockScope.children).toBe(mockComposition);
|
||||||
|
expect(mockScope.children.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("on changes in form values, updates the object model", function () {
|
||||||
|
var scopeConfiguration = mockScope.configuration,
|
||||||
|
model = mockDomainObject.getModel();
|
||||||
|
|
||||||
|
scopeConfiguration.plot.xAxis.key = 'lst';
|
||||||
|
scopeConfiguration.plot.yAxis.autoScale = true;
|
||||||
|
scopeConfiguration.plot.yAxis.key = 'eu';
|
||||||
|
|
||||||
|
expect(mockTopicObject.listen).toHaveBeenCalled();
|
||||||
|
mockTopicObject.listen.mostRecentCall.args[0]();
|
||||||
|
expect(mockDomainObject.useCapability).toHaveBeenCalledWith('mutation', jasmine.any(Function));
|
||||||
|
|
||||||
|
mockDomainObject.useCapability.mostRecentCall.args[1](model);
|
||||||
|
expect(model.configuration.plot.xAxis.key).toBe('lst');
|
||||||
|
expect(model.configuration.plot.yAxis.autoScale).toBe(true);
|
||||||
|
expect(model.configuration.plot.yAxis.key).toBe('eu');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cleans up listeners on destruction of the controller", function () {
|
||||||
|
mockScope.$on.mostRecentCall.args[1]();
|
||||||
|
expect(mockUnlisten).toHaveBeenCalled();
|
||||||
|
expect(mockFormUnlisten).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
73
platform/features/layout/test/PlotOptionsFormSpec.js
Normal file
73
platform/features/layout/test/PlotOptionsFormSpec.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,describe,it,expect,beforeEach,jasmine,xit*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../src/PlotOptionsForm'],
|
||||||
|
function (PlotOptionsForm) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The Plot Options form", function () {
|
||||||
|
var plotOptionsForm,
|
||||||
|
mockTopicFunction,
|
||||||
|
mockTopicObject,
|
||||||
|
listener;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
|
||||||
|
mockTopicObject = jasmine.createSpyObj('Topic', [
|
||||||
|
'listen',
|
||||||
|
'notify'
|
||||||
|
]);
|
||||||
|
mockTopicFunction = function() {
|
||||||
|
return mockTopicObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
plotOptionsForm = new PlotOptionsForm(mockTopicFunction);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defines form specs for x-axis, y-axis, and series data", function () {
|
||||||
|
expect(plotOptionsForm.xAxisForm).toBeDefined();
|
||||||
|
expect(plotOptionsForm.xAxisForm.sections).toBeDefined();
|
||||||
|
expect(plotOptionsForm.xAxisForm.sections[0].rows).toBeDefined();
|
||||||
|
expect(plotOptionsForm.xAxisForm.sections[0].rows.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
expect(plotOptionsForm.yAxisForm).toBeDefined();
|
||||||
|
expect(plotOptionsForm.plotSeriesForm).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses a topic to register listeners and inform them when a" +
|
||||||
|
" form value changes", function () {
|
||||||
|
var changedValue = 'changedValue';
|
||||||
|
|
||||||
|
expect(plotOptionsForm.xAxisForm.sections[0].rows[0].onchange).toBeDefined();
|
||||||
|
|
||||||
|
plotOptionsForm.listen(listener);
|
||||||
|
expect(mockTopicObject.listen).toHaveBeenCalledWith(listener);
|
||||||
|
|
||||||
|
plotOptionsForm.xAxisForm.sections[0].rows[0].onchange(changedValue);
|
||||||
|
expect(mockTopicObject.notify).toHaveBeenCalledWith(changedValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -23,6 +23,7 @@
|
|||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
name="mctControl"
|
name="mctControl"
|
||||||
ng-model="ngModel[field]"
|
ng-model="ngModel[field]"
|
||||||
|
ng-change="structure.onchange(ngModel[field])"
|
||||||
ng-disabled="ngDisabled">
|
ng-disabled="ngDisabled">
|
||||||
<em></em>
|
<em></em>
|
||||||
</label>
|
</label>
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
<input type="radio"
|
<input type="radio"
|
||||||
name="mctControl"
|
name="mctControl"
|
||||||
ng-model="ngModel[field]"
|
ng-model="ngModel[field]"
|
||||||
ng-disabled="ngDisabled">
|
ng-disabled="ngDisabled"
|
||||||
|
ng-change="structure.onchange(ngModel[field])"
|
||||||
|
ng-value="structure.value">
|
||||||
<em></em>
|
<em></em>
|
||||||
</label>
|
</label>
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
ng-model="ngModel[field]"
|
ng-model="ngModel[field]"
|
||||||
ng-options="opt.value as opt.name for opt in options"
|
ng-options="opt.value as opt.name for opt in options"
|
||||||
ng-required="ngRequired"
|
ng-required="ngRequired"
|
||||||
|
ng-change="structure.onchange(ngModel[field])"
|
||||||
name="mctControl">
|
name="mctControl">
|
||||||
<option value="" ng-show="!ngModel[field]">- Select One -</option>
|
<option value="" ng-show="!ngModel[field]">- Select One -</option>
|
||||||
</select>
|
</select>
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
ng-required="ngRequired"
|
ng-required="ngRequired"
|
||||||
ng-model="ngModel[field]"
|
ng-model="ngModel[field]"
|
||||||
ng-pattern="ngPattern"
|
ng-pattern="ngPattern"
|
||||||
|
ng-change="structure.onchange(ngModel[field])"
|
||||||
size="{{structure.size}}"
|
size="{{structure.size}}"
|
||||||
name="mctControl">
|
name="mctControl">
|
||||||
</span>
|
</span>
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<mct-control key="row.control"
|
<mct-control key="row.control"
|
||||||
ng-model="ngModel"
|
ng-model="ngModel"
|
||||||
ng-required="row.required"
|
ng-required="row.required"
|
||||||
|
ng-change="row.onchange"
|
||||||
ng-pattern="getRegExp(row.pattern)"
|
ng-pattern="getRegExp(row.pattern)"
|
||||||
options="row.options"
|
options="row.options"
|
||||||
structure="row"
|
structure="row"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user