Merge branch 'master' of github.com:nasa/openmct into open967

This commit is contained in:
David Hudson
2016-08-31 23:04:56 +09:00
80 changed files with 209 additions and 2899 deletions

View File

@@ -90,7 +90,9 @@ define(
// Ensure there is always a "save in" section
if (includeLocation) {
sections.push({
name: 'Location', rows: [{
name: 'Location',
cssclass: "grows",
rows: [{
name: "Save In",
control: "locator",
validate: validateLocation,

View File

@@ -50,10 +50,7 @@ define(
$scope.rootObject =
(context && context.getRoot()) || $scope.rootObject;
}, 0);
} else if (!contextRoot) {
//If no context root is available, default to the root
// object
$scope.rootObject = undefined;
} else if (!contextRoot && !$scope.rootObject) {
// Update the displayed tree on a timeout to avoid
// an infinite digest exception.
objectService.getObjects(['ROOT'])

View File

@@ -138,23 +138,34 @@ define(
});
});
describe("when no context is available", function () {
var defaultRoot = "DEFAULT_ROOT";
beforeEach(function () {
mockContext.getRoot.andReturn(undefined);
getObjectsPromise.then.andCallFake(function (callback) {
callback({'ROOT': defaultRoot});
});
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
});
it("provides a default context where none is available", function () {
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
mockTimeout.mostRecentCall.args[0]();
expect(mockScope.rootObject).toBe(defaultRoot);
var defaultRoot = "DEFAULT_ROOT";
beforeEach(function () {
mockContext.getRoot.andReturn(undefined);
getObjectsPromise.then.andCallFake(function (callback) {
callback({'ROOT': defaultRoot});
});
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
});
it("provides a default context where none is available", function () {
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
mockTimeout.mostRecentCall.args[0]();
expect(mockScope.rootObject).toBe(defaultRoot);
});
it("does not issue redundant requests for the root object", function () {
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
mockTimeout.mostRecentCall.args[0]();
mockScope.$watch.mostRecentCall.args[1](undefined);
mockTimeout.mostRecentCall.args[0]();
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
mockTimeout.mostRecentCall.args[0]();
expect(mockObjectService.getObjects.calls.length)
.toEqual(1);
});
});
});
}
);

View File

@@ -71,7 +71,7 @@
.form {
margin-bottom: $interiorMarginSm;
padding-bottom: $interiorMarginLg;
.form-section {
.l-section-body {
margin-bottom: 0;
&:not(.first) {
border-top: 1px solid $colorFormLines;

View File

@@ -25,11 +25,21 @@
.form {
color: $colorFormText;
height: 100%;
width: 100%;
.form-section {
position: relative;
margin-bottom: $interiorMarginLg * 2;
}
.l-form-section {
position: relative;
&.grows {
.l-section-body,
.form-row {
@include flex(1 1 auto);
.wrapper {
height: 100%;
}
}
}
}
.section-header {
border-radius: $basicCr;
@@ -43,10 +53,14 @@
.form-row {
$m: $interiorMargin;
box-sizing: border-box;
@include clearfix;
border-top: 1px solid $colorFormLines;
margin-bottom: $interiorMarginLg * 2;
padding: $formTBPad 0;
position: relative;
//&ng-form {
// display: block;
//}
&.first {
border-top: none;
}
@@ -92,17 +106,14 @@
.selector-list {
// Used in create overlay to display tree view
@include nice-input();
$h: 150px;
padding: $interiorMargin;
position: relative;
height: $h;
min-height: 150px;
height: 100%;
>.wrapper {
$p: $interiorMargin;
box-sizing: border-box;
overflow: auto;
position: absolute;
top: $p;
right: $p;
bottom: $p;
left: $p;
}
}
}

View File

@@ -21,9 +21,6 @@
*****************************************************************************/
//************************************************* GENERAL
.bubble-container {
pointer-events: none;
}
//************************************************* LAYOUT

View File

@@ -25,7 +25,6 @@
@include phone {
.overlay > .holder {
//@include test(orange); // This works!
$m: 0;
border-radius: $m;
top: $m;
@@ -38,36 +37,30 @@
overflow: auto;
@include transform(none);
.editor .form .form-row {
> .label,
> .controls {
//@include test(blue);
display: block;
float: none;
width: 100%;
}
> .label {
&:after {
float: none;
.editor .form .form-row.l-flex-row {
// Display elements in a columnar view
@include flex-direction(column);
> .flex-elem {
&:not(:first-child) {
margin-top: $interiorMargin;
}
&.label {
width: 100%;
}
&.controls {
overflow: auto;
}
}
}
.contents {
.abs.top-bar,
.abs.editor,
.abs.message-body,
.abs.bottom-bar {
//@include test(orange);
top: auto; right: auto; bottom: auto; left: auto;
height: auto; width: auto;
margin-bottom: $interiorMarginLg * 2;
&.validates > .label:before {
position: relative;
right: auto;
line-height: inherit;
margin-right: $interiorMargin;
}
}
}
.t-dialog-sm .overlay > .holder {
//@include test(blue);
height: auto; max-height: 100%;
}
}

View File

@@ -28,8 +28,10 @@ define([
function link(scope, element) {
var treeView = new TreeView(gestureService),
unobserve = treeView.observe(function (domainObject) {
scope.mctModel = domainObject;
scope.$apply();
if (scope.mctModel !== domainObject) {
scope.mctModel = domainObject;
scope.$apply();
}
});
element.append(angular.element(treeView.elements()));

View File

@@ -29,6 +29,18 @@ define([
mockExpr,
mctTree;
function makeMockDomainObject(id) {
var mockDomainObject = jasmine.createSpyObj('domainObject-' + id, [
'getId',
'getModel',
'getCapability',
'hasCapability'
]);
mockDomainObject.getId.andReturn(id);
mockDomainObject.getModel.andReturn({});
return mockDomainObject;
}
beforeEach(function () {
mockGestureService = jasmine.createSpyObj(
'gestureService',
@@ -56,7 +68,8 @@ define([
testAttrs;
beforeEach(function () {
mockScope = jasmine.createSpyObj('$scope', ['$watch', '$on']);
mockScope =
jasmine.createSpyObj('$scope', ['$watch', '$on', '$apply']);
mockElement = jasmine.createSpyObj('element', ['append']);
testAttrs = { mctModel: "some-expression" };
mockScope.$parent =
@@ -88,6 +101,27 @@ define([
jasmine.any(Function)
);
});
// https://github.com/nasa/openmct/issues/1114
it("does not trigger $apply during $watches", function () {
mockScope.mctObject = makeMockDomainObject('root');
mockScope.mctMode = makeMockDomainObject('selection');
mockScope.$watch.calls.forEach(function (call) {
call.args[1](mockScope[call.args[0]]);
});
expect(mockScope.$apply).not.toHaveBeenCalled();
});
it("does trigger $apply from other value changes", function () {
// White-boxy; we know this is the setter for the tree's value
var treeValueFn = mockScope.$watch.calls[0].args[1];
mockScope.mctObject = makeMockDomainObject('root');
mockScope.mctMode = makeMockDomainObject('selection');
treeValueFn(makeMockDomainObject('other'));
expect(mockScope.$apply).toHaveBeenCalled();
});
});
});

View File

@@ -29,8 +29,7 @@
define({
BUBBLE_TEMPLATE: "<mct-container key=\"bubble\" " +
"bubble-title=\"{{bubbleTitle}}\" " +
"bubble-layout=\"{{bubbleLayout}}\" " +
"class=\"bubble-container\">" +
"bubble-layout=\"{{bubbleLayout}}\">" +
"<mct-include key=\"bubbleTemplate\" " +
"ng-model=\"bubbleModel\">" +
"</mct-include>" +

View File

@@ -95,7 +95,7 @@ define(
this.locationService = locationService;
this.composeService = composeService;
this.verb = verb || "Compose";
this.suffix = suffix || "to a new location";
this.suffix = suffix || "To a New Location";
}
AbstractComposeAction.prototype.cloneContext = function () {

View File

@@ -54,7 +54,7 @@ define(
copyService,
context,
"Duplicate",
"to a location"
"To a Location"
);
}

View File

@@ -58,6 +58,7 @@ define(
sections: [
{
name: 'Location',
cssclass: "grows",
rows: [
{
name: label,

View File

@@ -150,7 +150,7 @@ define(
it("prompts for location", function () {
expect(locationService.getLocationFromUser)
.toHaveBeenCalledWith(
"Compose selectedObject to a new location",
"Compose selectedObject To a New Location",
"Compose To",
jasmine.any(Function),
currentParent

View File

@@ -173,7 +173,7 @@ define(
it("prompts for location", function () {
expect(locationService.getLocationFromUser)
.toHaveBeenCalledWith(
"Duplicate selectedObject to a location",
"Duplicate selectedObject To a Location",
"Duplicate To",
jasmine.any(Function),
currentParent

View File

@@ -126,7 +126,7 @@ define(
it("prompts for location", function () {
expect(locationService.getLocationFromUser)
.toHaveBeenCalledWith(
"Link selectedObject to a new location",
"Link selectedObject To a New Location",
"Link To",
jasmine.any(Function),
currentParent

View File

@@ -126,7 +126,7 @@ define(
it("prompts for location", function () {
expect(locationService.getLocationFromUser)
.toHaveBeenCalledWith(
"Move selectedObject to a new location",
"Move selectedObject To a New Location",
"Move To",
jasmine.any(Function),
currentParent

View File

@@ -139,6 +139,7 @@ define([
"dialog": {
"control": "textfield",
"name": "Image URL",
"cssclass": "l-input-lg",
"required": true
}
},
@@ -213,12 +214,12 @@ define([
{
"name": "Horizontal grid (px)",
"control": "textfield",
"cssclass": "l-small l-numeric"
"cssclass": "l-input-sm l-numeric"
},
{
"name": "Vertical grid (px)",
"control": "textfield",
"cssclass": "l-small l-numeric"
"cssclass": "l-input-sm l-numeric"
}
],
"pattern": "^(\\d*[1-9]\\d*)?$",

View File

@@ -169,6 +169,7 @@ define([
"dialog": {
"control": "textfield",
"name": "Image URL",
"cssclass": "l-input-lg",
"required": true
}
},
@@ -329,12 +330,12 @@ define([
{
"name": "Horizontal grid (px)",
"control": "textfield",
"cssclass": "l-small l-numeric"
"cssclass": "l-input-sm l-numeric"
},
{
"name": "Vertical grid (px)",
"control": "textfield",
"cssclass": "l-small l-numeric"
"cssclass": "l-input-sm l-numeric"
}
],
"pattern": "^(\\d*[1-9]\\d*)?$",

View File

@@ -55,6 +55,7 @@ define(
key: "url",
control: "textfield",
name: "Image URL",
"cssclass": "l-input-lg",
required: true
}
]

View File

@@ -19,39 +19,39 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<form name="mctForm" novalidate class="form">
<span ng-repeat="section in structure.sections">
<div class="section-header" ng-if="section.name">
<form name="mctForm" novalidate class="form l-flex-col">
<span ng-repeat="section in structure.sections"
class="l-form-section l-flex-col flex-elem {{ section.cssclass }}">
<div class="section-header flex-elem" ng-if="section.name">
{{section.name}}
</div>
<div class="form-section" ng-class="{ first:$index < 1 }">
<ng-form name="mctFormInner" ng-repeat="row in section.rows">
<div class="form-row validates l-flex-row"
ng-class="{
req: row.required,
valid: mctFormInner.$dirty && mctFormInner.$valid,
invalid: mctFormInner.$dirty && !mctFormInner.$valid,
first: $index < 1,
'l-controls-first': row.layout === 'control-first',
'l-controls-under': row.layout === 'controls-under'
}">
<div class='label flex-elem' title="{{row.description}}">
{{row.name}}
</div>
<div class='controls flex-elem'>
<div class="wrapper" ng-if="row.control">
<mct-control key="row.control"
ng-model="ngModel"
ng-required="row.required"
ng-pattern="getRegExp(row.pattern)"
options="row.options"
structure="row"
field="row.key">
</mct-control>
</div>
</div>
<ng-form class="form-row validates l-flex-row flex-elem {{ section.cssclass }}"
ng-class="{
first:$index < 1,
req: row.required,
valid: mctFormInner.$dirty && mctFormInner.$valid,
invalid: mctFormInner.$dirty && !mctFormInner.$valid,
first: $index < 1,
'l-controls-first': row.layout === 'control-first',
'l-controls-under': row.layout === 'controls-under'
}"
name="mctFormInner"
ng-repeat="row in section.rows">
<div class='label flex-elem' title="{{row.description}}">
{{row.name}}
</div>
<div class='controls flex-elem'>
<div class="wrapper" ng-if="row.control">
<mct-control key="row.control"
ng-model="ngModel"
ng-required="row.required"
ng-pattern="getRegExp(row.pattern)"
options="row.options"
structure="row"
field="row.key">
</mct-control>
</div>
</ng-form>
</div>
</div>
</ng-form>
</span>
</form>

View File

@@ -80,7 +80,7 @@ define(function () {
// If there's still nothing in the filters string, there are no
// filters selected
if ($scope.ngModel.filtersString === '') {
$scope.ngModel.filtersString = 'NONE';
$scope.ngModel.checkAll = true;
}
}
@@ -95,12 +95,11 @@ define(function () {
$scope.ngModel.checked[type] = false;
});
// Change the filters string depending on checkAll status
if ($scope.ngModel.checkAll) {
// This setting will make the filters display hidden
$scope.ngModel.filtersString = '';
} else {
$scope.ngModel.filtersString = 'NONE';
// This setting will make the filters display hidden
$scope.ngModel.filtersString = '';
// Do not let checkAll become unchecked when it is the only checked filter
if (!$scope.ngModel.checkAll) {
$scope.ngModel.checkAll = true;
}
// Re-filter results

View File

@@ -76,14 +76,16 @@ define(
expect(mockScope.ngModel.filtersString).not.toEqual('');
});
it("changing checkAll status updates the filter string", function () {
it("changing checkAll status sets checkAll to true", function () {
controller.checkAll();
expect(mockScope.ngModel.checkAll).toEqual(true);
expect(mockScope.ngModel.filtersString).toEqual('');
mockScope.ngModel.checkAll = false;
controller.checkAll();
expect(mockScope.ngModel.filtersString).toEqual('NONE');
expect(mockScope.ngModel.checkAll).toEqual(true);
expect(mockScope.ngModel.filtersString).toEqual('');
});
it("checking checkAll option resets other options", function () {
@@ -97,7 +99,7 @@ define(
});
});
it("tells the user when no options are checked", function () {
it("checks checkAll when no options are checked", function () {
Object.keys(mockScope.ngModel.checked).forEach(function (type) {
mockScope.ngModel.checked[type] = false;
});
@@ -105,7 +107,8 @@ define(
controller.updateOptions();
expect(mockScope.ngModel.filtersString).toEqual('NONE');
expect(mockScope.ngModel.filtersString).toEqual('');
expect(mockScope.ngModel.checkAll).toEqual(true);
});
it("tells the user when options are checked", function () {
@@ -116,7 +119,6 @@ define(
controller.updateOptions();
expect(mockScope.ngModel.filtersString).not.toEqual('NONE');
expect(mockScope.ngModel.filtersString).not.toEqual('');
});
});