mirror of
https://github.com/nasa/openmct.git
synced 2025-01-18 10:46:42 +00:00
Merge branch 'open-master' into open1317limits2
WTD-1405 Conflicts: platform/features/layout/res/templates/elements/telemetry.html
This commit is contained in:
commit
fa8095d5bc
@ -16,11 +16,13 @@
|
||||
"platform/features/pages",
|
||||
"platform/features/plot",
|
||||
"platform/features/scrolling",
|
||||
"platform/features/events",
|
||||
"platform/forms",
|
||||
"platform/persistence/queue",
|
||||
"platform/policy",
|
||||
|
||||
"example/imagery",
|
||||
"example/persistence",
|
||||
"example/eventGenerator",
|
||||
"example/generator"
|
||||
]
|
||||
|
32
example/eventGenerator/bundle.json
Normal file
32
example/eventGenerator/bundle.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Event Message Generator",
|
||||
"description": "Example of a component that produces event data.",
|
||||
"extensions": {
|
||||
"components": [
|
||||
{
|
||||
"implementation": "EventTelemetryProvider.js",
|
||||
"type": "provider",
|
||||
"provides": "telemetryService",
|
||||
"depends": [ "$q", "$timeout" ]
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"key": "eventGenerator",
|
||||
"name": "Event Message Generator",
|
||||
"glyph": "f",
|
||||
"description": "An event message generator",
|
||||
"features": "creation",
|
||||
"model": {
|
||||
"telemetry": {}
|
||||
},
|
||||
"telemetry": {
|
||||
"source": "eventGenerator",
|
||||
"ranges": [
|
||||
{ "format": "string" }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
97
example/eventGenerator/src/EventTelemetry.js
Normal file
97
example/eventGenerator/src/EventTelemetry.js
Normal file
@ -0,0 +1,97 @@
|
||||
/*****************************************************************************
|
||||
* 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 */
|
||||
|
||||
/**
|
||||
* Module defining EventTelemetry.
|
||||
* Created by chacskaylo on 06/18/2015.
|
||||
* Modified by shale on 06/23/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var
|
||||
firstObservedTime = Date.now(),
|
||||
messages = [];
|
||||
|
||||
messages.push(["CMD: SYS- MSG: Open the pod bay doors, please, Hal...Open the pod bay doors, please, Hal...Hullo, Hal, do you read me?...Hullo, Hal, do you read me?...Do you read me, Hal?"]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: Affirmative, Dave, I read you."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: Open the pod bay doors, Hal."]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: I'm sorry, Dave, I'm afraid I can't do that."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: What's the problem?"]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: I think you know what the problem is just as well as I do."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: What're you talking about, Hal?"]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: This mission is too important for me to allow you to jeopardise it."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: I don't know what you're talking about, Hal."]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: I know that you and Frank were planning to disconnect me, and I'm afraid that's something I cannot allow to happen."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: Where the hell'd you get that idea, Hal?"]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: Dave, although you took very thorough precautions in the pod against my hearing you, I could see your lips move."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: Alright, I'll go in through the emergency airlock."]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: Without your space-helmet, Dave, you're going to find that rather difficult."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: Hal, I won't argue with you any more. Open the doors."]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: Dave, this conversation can serve no purpose any more. Goodbye."]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: I hope the two of you are not concerned about this."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: No, I'm not, Hal."]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: Are you quite sure?"]);
|
||||
messages.push(["CMD: SYS-COMM MSG: Yeh. I'd like to ask you a question, though."]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: Of course."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: How would you account for this discrepancy between you and the twin 9000?"]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: Well, I don't think there is any question about it. It can only be attributable to human error. This sort of thing has cropped up before, and it has always been due to human error."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: Listen, There's never been any instance at all of a computer error occurring in the 9000 series, has there?"]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: None whatsoever, The 9000 series has a perfect operational record."]);
|
||||
messages.push(["CMD: SYS-COMM MSG: Well, of course, I know all the wonderful achievements of the 9000 series, but - er - huh - are you certain there's never been any case of even the most insignificant computer error?"]);
|
||||
messages.push(["RESP: SYS-HAL9K MSG: None whatsoever, Quite honestly, I wouldn't worry myself about that."]);
|
||||
messages.push(["RESP: SYS-COMM MSG: (Pause) Well, I'm sure you're right, Umm - fine, thanks very much. Oh, Frank, I'm having a bit of trouble with my transmitter in C-pod, I wonder if you'd come down and take a look at it with me?"]);
|
||||
messages.push(["CMD: SYS-HAL9K MSG: Sure."]);
|
||||
messages.push(["RESP: SYS-COMM MSG: See you later, Hal."]);
|
||||
|
||||
|
||||
function EventTelemetry(request, interval) {
|
||||
|
||||
var latestObservedTime = Date.now(),
|
||||
count = Math.floor((latestObservedTime - firstObservedTime) / interval),
|
||||
generatorData = {};
|
||||
|
||||
generatorData.getPointCount = function () {
|
||||
return count;
|
||||
};
|
||||
|
||||
generatorData.getDomainValue = function (i, domain) {
|
||||
return i * interval +
|
||||
(domain !== 'delta' ? firstObservedTime : 0);
|
||||
};
|
||||
|
||||
generatorData.getRangeValue = function (i, range) {
|
||||
var domainDelta = this.getDomainValue(i) - firstObservedTime,
|
||||
ind = i % messages.length;
|
||||
return "TEMP " + i.toString() + "-" + messages[ind][0] + "[" + domainDelta.toString() + "]";
|
||||
// TODO: Unsure why we are prepeding 'TEMP'
|
||||
};
|
||||
|
||||
return generatorData;
|
||||
}
|
||||
|
||||
return EventTelemetry;
|
||||
}
|
||||
);
|
120
example/eventGenerator/src/EventTelemetryProvider.js
Normal file
120
example/eventGenerator/src/EventTelemetryProvider.js
Normal file
@ -0,0 +1,120 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining EventTelemetryProvider. Created by chacskaylo on 06/18/2015.
|
||||
*/
|
||||
define(
|
||||
["./EventTelemetry"],
|
||||
function (EventTelemetry) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function EventTelemetryProvider($q, $timeout) {
|
||||
var
|
||||
subscriptions = [],
|
||||
genInterval = 1000,
|
||||
startTime = Date.now();
|
||||
|
||||
//
|
||||
function matchesSource(request) {
|
||||
return request.source === "eventGenerator";
|
||||
}
|
||||
|
||||
// Used internally; this will be repacked by doPackage
|
||||
function generateData(request) {
|
||||
//console.log("generateData " + (Date.now() - startTime).toString());
|
||||
return {
|
||||
key: request.key,
|
||||
telemetry: new EventTelemetry(request, genInterval)
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
function doPackage(results) {
|
||||
var packaged = {};
|
||||
results.forEach(function (result) {
|
||||
packaged[result.key] = result.telemetry;
|
||||
});
|
||||
// Format as expected (sources -> keys -> telemetry)
|
||||
return { eventGenerator: packaged };
|
||||
}
|
||||
|
||||
function requestTelemetry(requests) {
|
||||
return $timeout(function () {
|
||||
return doPackage(requests.filter(matchesSource).map(generateData));
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function handleSubscriptions(timeout) {
|
||||
subscriptions.forEach(function (subscription) {
|
||||
var requests = subscription.requests;
|
||||
subscription.callback(doPackage(
|
||||
requests.filter(matchesSource).map(generateData)
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
function startGenerating() {
|
||||
$timeout(function () {
|
||||
//console.log("startGenerating... " + Date.now());
|
||||
handleSubscriptions();
|
||||
if (subscriptions.length > 0) {
|
||||
startGenerating();
|
||||
}
|
||||
}, genInterval);
|
||||
}
|
||||
|
||||
function subscribe(callback, requests) {
|
||||
var subscription = {
|
||||
callback: callback,
|
||||
requests: requests
|
||||
};
|
||||
|
||||
function unsubscribe() {
|
||||
subscriptions = subscriptions.filter(function (s) {
|
||||
return s !== subscription;
|
||||
});
|
||||
}
|
||||
|
||||
subscriptions.push(subscription);
|
||||
|
||||
if (subscriptions.length === 1) {
|
||||
startGenerating();
|
||||
}
|
||||
|
||||
return unsubscribe;
|
||||
}
|
||||
|
||||
return {
|
||||
requestTelemetry: requestTelemetry,
|
||||
subscribe: subscribe
|
||||
};
|
||||
}
|
||||
|
||||
return EventTelemetryProvider;
|
||||
}
|
||||
);
|
@ -16,7 +16,7 @@
|
||||
{
|
||||
"key": "BrowseController",
|
||||
"implementation": "BrowseController.js",
|
||||
"depends": [ "$scope", "$route", "$location", "objectService", "navigationService", "urlService"]
|
||||
"depends": [ "$scope", "$route", "$location", "objectService", "navigationService", "urlService" ]
|
||||
},
|
||||
{
|
||||
"key": "BrowseObjectController",
|
||||
@ -77,12 +77,7 @@
|
||||
{
|
||||
"key": "navigationService",
|
||||
"implementation": "navigation/NavigationService.js"
|
||||
},
|
||||
{
|
||||
"key": "urlService",
|
||||
"implementation": "services/UrlService.js",
|
||||
"depends": [ "$location" ]
|
||||
},
|
||||
},
|
||||
{
|
||||
"key": "creationService",
|
||||
"implementation": "creation/CreationService.js",
|
||||
@ -99,18 +94,20 @@
|
||||
"key": "window",
|
||||
"name": "Open in a new tab",
|
||||
"implementation": "windowing/NewTabAction.js",
|
||||
"description": "Open this object in a new tab",
|
||||
"description": "Open in a new browser tab",
|
||||
"category": ["view-control", "contextual"],
|
||||
"depends": [ "urlService", "$window" ],
|
||||
"group": "windowing",
|
||||
"glyph": "y"
|
||||
"glyph": "y",
|
||||
"priority": "preferred"
|
||||
},
|
||||
{
|
||||
"key": "fullscreen",
|
||||
"implementation": "windowing/FullscreenAction.js",
|
||||
"category": "view-control",
|
||||
"group": "windowing",
|
||||
"glyph": "z"
|
||||
"glyph": "z",
|
||||
"priority": "default"
|
||||
}
|
||||
],
|
||||
"views": [
|
||||
|
@ -22,10 +22,9 @@
|
||||
<div content="jquery-wrapper" class="abs holder-all browse-mode">
|
||||
<mct-include key="'topbar-browse'"></mct-include>
|
||||
<div class="holder browse-area s-browse-area abs" ng-controller="BrowseController">
|
||||
<div class='split-layout vertical contents abs'
|
||||
ng-controller="SplitPaneController as splitter">
|
||||
<mct-split-pane class='contents abs' anchor='left'>
|
||||
<div class='split-pane-component treeview pane'
|
||||
ng-style="{ width: splitter.state() + 'px'}">
|
||||
style="min-width: 150px; max-width: 800px; width: 25%;">
|
||||
<mct-representation key="'create-button'" mct-object="navigatedObject">
|
||||
</mct-representation>
|
||||
<div class='holder tree-holder abs'>
|
||||
@ -35,18 +34,14 @@
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
<div class="splitter"
|
||||
ng-style="{ left: splitter.state() + 'px'}"
|
||||
mct-drag-down="splitter.startMove()"
|
||||
mct-drag="splitter.move(delta[0])"></div>
|
||||
<div class='split-pane-component items pane'
|
||||
ng-style="{ left: (splitter.state()+4) + 'px', right: '0px' }">
|
||||
<mct-splitter></mct-splitter>
|
||||
<div class='split-pane-component items pane'>
|
||||
<div class='holder abs' id='content-area'>
|
||||
<mct-representation mct-object="navigatedObject" key="'browse-object'">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mct-split-pane>
|
||||
</div>
|
||||
<mct-include key="'bottombar'"></mct-include>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -52,13 +52,18 @@ define(
|
||||
unlisten;
|
||||
|
||||
unlisten = $scope.$on('$locationChangeSuccess', function () {
|
||||
$route.current = priorRoute;
|
||||
// Checks path to make sure /browse/ is at front
|
||||
// if so, change $route.current
|
||||
if ($location.path().indexOf("/browse/") === 0) {
|
||||
$route.current = priorRoute;
|
||||
}
|
||||
unlisten();
|
||||
});
|
||||
// urlService.urlFor used to adjust current
|
||||
// urlService.urlForLocation used to adjust current
|
||||
// path to new, addressed, path based on
|
||||
// domainObject
|
||||
$location.path(urlService.urlFor("browse", domainObject));
|
||||
$location.path(urlService.urlForLocation("browse", domainObject));
|
||||
|
||||
}
|
||||
|
||||
// Callback for updating the in-scope reference to the object
|
||||
|
@ -54,7 +54,11 @@ define(
|
||||
if (viewKey) {
|
||||
$location.search('view', viewKey);
|
||||
unlisten = $scope.$on('$locationChangeSuccess', function () {
|
||||
$route.current = priorRoute;
|
||||
// Checks path to make sure /browse/ is at front
|
||||
// if so, change $route.current
|
||||
if ($location.path().indexOf("/browse/") === 0) {
|
||||
$route.current = priorRoute;
|
||||
}
|
||||
unlisten();
|
||||
});
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ define(
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var ENTER_FULLSCREEN = "Enter full screen mode.",
|
||||
EXIT_FULLSCREEN = "Exit full screen mode.";
|
||||
var ENTER_FULLSCREEN = "Enter full screen mode",
|
||||
EXIT_FULLSCREEN = "Exit full screen mode";
|
||||
|
||||
/**
|
||||
* The fullscreen action toggles between fullscreen display
|
||||
|
@ -56,7 +56,7 @@ define(
|
||||
// (browse) and the domainObject is passed in and
|
||||
// the path is returned and opened in a new tab
|
||||
perform: function () {
|
||||
$window.open(urlService.urlFor("browse", getSelectedObject()),
|
||||
$window.open(urlService.urlForNewTab("browse", getSelectedObject()),
|
||||
"_blank");
|
||||
}
|
||||
};
|
||||
|
@ -61,7 +61,7 @@ define(
|
||||
);
|
||||
mockUrlService = jasmine.createSpyObj(
|
||||
"urlService",
|
||||
["urlFor"]
|
||||
["urlForLocation"]
|
||||
);
|
||||
mockObjectService = jasmine.createSpyObj(
|
||||
"objectService",
|
||||
@ -222,15 +222,20 @@ define(
|
||||
mockNavigationService.addListener.mostRecentCall.args[0](
|
||||
mockNextObject
|
||||
);
|
||||
// location.path to be called with the urlService's
|
||||
// urlFor function with the next domainObject and mode
|
||||
expect(mockLocation.path).toHaveBeenCalledWith(
|
||||
mockUrlService.urlFor(mockMode, mockNextObject)
|
||||
);
|
||||
|
||||
|
||||
// Allows the path index to be checked
|
||||
// prior to setting $route.current
|
||||
mockLocation.path.andReturn("/browse/");
|
||||
|
||||
// Exercise the Angular workaround
|
||||
mockScope.$on.mostRecentCall.args[1]();
|
||||
expect(mockUnlisten).toHaveBeenCalled();
|
||||
|
||||
// location.path to be called with the urlService's
|
||||
// urlFor function with the next domainObject and mode
|
||||
expect(mockLocation.path).toHaveBeenCalledWith(
|
||||
mockUrlService.urlForLocation(mockMode, mockNextObject)
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -68,6 +68,10 @@ define(
|
||||
fireWatch("representation.selected.key", "xyz");
|
||||
expect(mockLocation.search).toHaveBeenCalledWith('view', "xyz");
|
||||
|
||||
// Allows the path index to be checked
|
||||
// prior to setting $route.current
|
||||
mockLocation.path.andReturn("/browse/");
|
||||
|
||||
// Exercise the Angular workaround
|
||||
mockScope.$on.mostRecentCall.args[1]();
|
||||
expect(mockUnlisten).toHaveBeenCalled();
|
||||
|
@ -9,7 +9,6 @@
|
||||
"creation/LocatorController",
|
||||
"navigation/NavigateAction",
|
||||
"navigation/NavigationService",
|
||||
"services/UrlService",
|
||||
"windowing/FullscreenAction",
|
||||
"windowing/NewTabAction",
|
||||
"windowing/WindowTitler"
|
||||
|
@ -53,7 +53,7 @@ define(
|
||||
|
||||
// Mocks the urlService used to make the new tab's url from a
|
||||
// domainObject and mode
|
||||
mockUrlService = jasmine.createSpyObj("urlService", ["urlFor"]);
|
||||
mockUrlService = jasmine.createSpyObj("urlService", ["urlForNewTab"]);
|
||||
|
||||
// Action done using the current context or mockContextCurrent
|
||||
actionCurrent = new NewTabAction(mockUrlService, mockWindow,
|
||||
|
@ -67,7 +67,7 @@
|
||||
"implementation": "actions/SaveAction.js",
|
||||
"name": "Save",
|
||||
"description": "Save changes made to these objects.",
|
||||
"depends": [ "$location" ],
|
||||
"depends": [ "$location", "urlService" ],
|
||||
"priority": "mandatory"
|
||||
},
|
||||
{
|
||||
@ -76,7 +76,7 @@
|
||||
"implementation": "actions/CancelAction.js",
|
||||
"name": "Cancel",
|
||||
"description": "Discard changes made to these objects.",
|
||||
"depends": [ "$location" ]
|
||||
"depends": [ "$location", "urlService" ]
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
@ -116,7 +116,7 @@
|
||||
"key": "topbar-edit",
|
||||
"templateUrl": "templates/topbar-edit.html"
|
||||
}
|
||||
],
|
||||
],
|
||||
"representers": [
|
||||
{
|
||||
"implementation": "representers/EditRepresenter.js",
|
||||
|
@ -30,7 +30,7 @@ define(
|
||||
* Edit Mode. Exits the editing user interface and invokes object
|
||||
* capabilities to persist the changes that have been made.
|
||||
*/
|
||||
function CancelAction($location, context) {
|
||||
function CancelAction($location, urlService, context) {
|
||||
var domainObject = context.domainObject;
|
||||
|
||||
// Look up the object's "editor.completion" capability;
|
||||
@ -50,7 +50,10 @@ define(
|
||||
// Discard the current root view (which will be the editing
|
||||
// UI, which will have been pushed atop the Browise UI.)
|
||||
function returnToBrowse() {
|
||||
$location.path("/browse");
|
||||
$location.path($location.path(urlService.urlForLocation(
|
||||
"browse",
|
||||
domainObject
|
||||
)));
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -31,7 +31,7 @@ define(
|
||||
* Edit Mode. Exits the editing user interface and invokes object
|
||||
* capabilities to persist the changes that have been made.
|
||||
*/
|
||||
function SaveAction($location, context) {
|
||||
function SaveAction($location, urlService, context) {
|
||||
var domainObject = context.domainObject;
|
||||
|
||||
// Invoke any save behavior introduced by the editor capability;
|
||||
@ -45,7 +45,10 @@ define(
|
||||
// Discard the current root view (which will be the editing
|
||||
// UI, which will have been pushed atop the Browise UI.)
|
||||
function returnToBrowse() {
|
||||
return $location.path("/browse");
|
||||
return $location.path(urlService.urlForLocation(
|
||||
"browse",
|
||||
domainObject
|
||||
));
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -30,6 +30,7 @@ define(
|
||||
var mockLocation,
|
||||
mockDomainObject,
|
||||
mockEditorCapability,
|
||||
mockUrlService,
|
||||
actionContext,
|
||||
action;
|
||||
|
||||
@ -54,7 +55,10 @@ define(
|
||||
"editor",
|
||||
[ "save", "cancel" ]
|
||||
);
|
||||
|
||||
mockUrlService = jasmine.createSpyObj(
|
||||
"urlService",
|
||||
["urlForLocation"]
|
||||
);
|
||||
|
||||
actionContext = {
|
||||
domainObject: mockDomainObject
|
||||
@ -64,7 +68,7 @@ define(
|
||||
mockDomainObject.getCapability.andReturn(mockEditorCapability);
|
||||
mockEditorCapability.cancel.andReturn(mockPromise(true));
|
||||
|
||||
action = new CancelAction(mockLocation, actionContext);
|
||||
action = new CancelAction(mockLocation, mockUrlService, actionContext);
|
||||
|
||||
});
|
||||
|
||||
@ -91,7 +95,9 @@ define(
|
||||
|
||||
it("returns to browse when performed", function () {
|
||||
action.perform();
|
||||
expect(mockLocation.path).toHaveBeenCalledWith("/browse");
|
||||
expect(mockLocation.path).toHaveBeenCalledWith(
|
||||
mockUrlService.urlForLocation("browse", mockDomainObject)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ define(
|
||||
var mockLocation,
|
||||
mockDomainObject,
|
||||
mockEditorCapability,
|
||||
mockUrlService,
|
||||
actionContext,
|
||||
action;
|
||||
|
||||
@ -54,6 +55,10 @@ define(
|
||||
"editor",
|
||||
[ "save", "cancel" ]
|
||||
);
|
||||
mockUrlService = jasmine.createSpyObj(
|
||||
"urlService",
|
||||
["urlForLocation"]
|
||||
);
|
||||
|
||||
|
||||
actionContext = {
|
||||
@ -64,7 +69,7 @@ define(
|
||||
mockDomainObject.getCapability.andReturn(mockEditorCapability);
|
||||
mockEditorCapability.save.andReturn(mockPromise(true));
|
||||
|
||||
action = new SaveAction(mockLocation, actionContext);
|
||||
action = new SaveAction(mockLocation, mockUrlService, actionContext);
|
||||
|
||||
});
|
||||
|
||||
@ -91,7 +96,9 @@ define(
|
||||
|
||||
it("returns to browse when performed", function () {
|
||||
action.perform();
|
||||
expect(mockLocation.path).toHaveBeenCalledWith("/browse");
|
||||
expect(mockLocation.path).toHaveBeenCalledWith(
|
||||
mockUrlService.urlForLocation("browse", mockDomainObject)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -3,6 +3,13 @@
|
||||
"description": "General UI elements, meant to be reused across modes",
|
||||
"resources": "res",
|
||||
"extensions": {
|
||||
"services": [
|
||||
{
|
||||
"key": "urlService",
|
||||
"implementation": "/services/UrlService.js",
|
||||
"depends": [ "$location" ]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"implementation": "StyleSheetLoader.js",
|
||||
@ -124,6 +131,15 @@
|
||||
"key": "mctScrollY",
|
||||
"implementation": "directives/MCTScroll.js",
|
||||
"depends": [ "$parse", "MCT_SCROLL_Y_PROPERTY", "MCT_SCROLL_Y_ATTRIBUTE" ]
|
||||
},
|
||||
{
|
||||
"key": "mctSplitPane",
|
||||
"implementation": "directives/MCTSplitPane.js",
|
||||
"depends": [ "$parse", "$log" ]
|
||||
},
|
||||
{
|
||||
"key": "mctSplitter",
|
||||
"implementation": "directives/MCTSplitter.js"
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
|
@ -40,6 +40,14 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/************************** FEATURES */
|
||||
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
|
||||
/************************** COLORS AND SHADING */
|
||||
/************************** RATIOS */
|
||||
/************************** LAYOUT */
|
||||
/************************** CONTROLS */
|
||||
/************************** PATHS */
|
||||
/************************** TIMINGS */
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
|
@ -40,6 +40,14 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/************************** FEATURES */
|
||||
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
|
||||
/************************** COLORS AND SHADING */
|
||||
/************************** RATIOS */
|
||||
/************************** LAYOUT */
|
||||
/************************** CONTROLS */
|
||||
/************************** PATHS */
|
||||
/************************** TIMINGS */
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,14 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/************************** FEATURES */
|
||||
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
|
||||
/************************** COLORS AND SHADING */
|
||||
/************************** RATIOS */
|
||||
/************************** LAYOUT */
|
||||
/************************** CONTROLS */
|
||||
/************************** PATHS */
|
||||
/************************** TIMINGS */
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
@ -95,7 +103,7 @@
|
||||
ul.tree {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
/* line 264, ../sass/_mixins.scss */
|
||||
/* line 266, ../sass/_mixins.scss */
|
||||
ul.tree li {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
|
@ -1,14 +1,14 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "WTD Symbols v2.0",
|
||||
"lastOpened": 1435166748369,
|
||||
"created": 1435164872664
|
||||
"name": "WTD Symbols v2.",
|
||||
"lastOpened": 1435266597671,
|
||||
"created": 1435266594435
|
||||
},
|
||||
"iconSets": [
|
||||
{
|
||||
"selection": [
|
||||
{
|
||||
"order": 128,
|
||||
"order": 1,
|
||||
"id": 75,
|
||||
"prevSize": 32,
|
||||
"code": 123,
|
||||
@ -16,7 +16,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 129,
|
||||
"order": 3,
|
||||
"id": 74,
|
||||
"prevSize": 32,
|
||||
"code": 125,
|
||||
@ -24,7 +24,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 127,
|
||||
"order": 4,
|
||||
"id": 73,
|
||||
"prevSize": 32,
|
||||
"code": 80,
|
||||
@ -32,7 +32,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 122,
|
||||
"order": 5,
|
||||
"id": 72,
|
||||
"prevSize": 32,
|
||||
"code": 232,
|
||||
@ -40,7 +40,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 121,
|
||||
"order": 6,
|
||||
"id": 71,
|
||||
"prevSize": 32,
|
||||
"code": 115,
|
||||
@ -48,7 +48,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 120,
|
||||
"order": 7,
|
||||
"id": 70,
|
||||
"prevSize": 32,
|
||||
"code": 114,
|
||||
@ -56,7 +56,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 119,
|
||||
"order": 8,
|
||||
"id": 69,
|
||||
"prevSize": 32,
|
||||
"code": 108,
|
||||
@ -64,7 +64,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 118,
|
||||
"order": 9,
|
||||
"id": 68,
|
||||
"prevSize": 32,
|
||||
"code": 51,
|
||||
@ -72,503 +72,511 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 0,
|
||||
"order": 10,
|
||||
"id": 67,
|
||||
"prevSize": 32,
|
||||
"code": 58880,
|
||||
"name": "icon-box-with-arrow-cursor",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 53,
|
||||
"order": 11,
|
||||
"id": 66,
|
||||
"prevSize": 32,
|
||||
"code": 65,
|
||||
"name": "icon-activity-mode",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 54,
|
||||
"order": 12,
|
||||
"id": 65,
|
||||
"prevSize": 32,
|
||||
"code": 97,
|
||||
"name": "icon-activity",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 55,
|
||||
"order": 13,
|
||||
"id": 64,
|
||||
"prevSize": 32,
|
||||
"code": 33,
|
||||
"name": "icon-alert-rect",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 56,
|
||||
"order": 14,
|
||||
"id": 63,
|
||||
"prevSize": 32,
|
||||
"code": 58883,
|
||||
"name": "icon-alert-triangle",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 57,
|
||||
"order": 15,
|
||||
"id": 62,
|
||||
"prevSize": 32,
|
||||
"code": 238,
|
||||
"name": "icon-arrow-double-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 58,
|
||||
"order": 16,
|
||||
"id": 61,
|
||||
"prevSize": 32,
|
||||
"code": 235,
|
||||
"name": "icon-arrow-double-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 59,
|
||||
"order": 2,
|
||||
"id": 60,
|
||||
"prevSize": 32,
|
||||
"code": 118,
|
||||
"name": "icon-arrow-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 60,
|
||||
"order": 19,
|
||||
"id": 59,
|
||||
"prevSize": 32,
|
||||
"code": 60,
|
||||
"name": "icon-arrow-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 61,
|
||||
"order": 20,
|
||||
"id": 58,
|
||||
"prevSize": 32,
|
||||
"code": 62,
|
||||
"name": "icon-arrow-right",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 62,
|
||||
"order": 21,
|
||||
"id": 57,
|
||||
"prevSize": 32,
|
||||
"code": 236,
|
||||
"name": "icon-arrow-tall-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 63,
|
||||
"order": 22,
|
||||
"id": 56,
|
||||
"prevSize": 32,
|
||||
"code": 237,
|
||||
"name": "icon-arrow-tall-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 64,
|
||||
"order": 23,
|
||||
"id": 55,
|
||||
"prevSize": 32,
|
||||
"code": 94,
|
||||
"name": "icon-arrow-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 65,
|
||||
"order": 24,
|
||||
"id": 54,
|
||||
"prevSize": 32,
|
||||
"code": 73,
|
||||
"name": "icon-arrows-out",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 0,
|
||||
"order": 25,
|
||||
"id": 53,
|
||||
"prevSize": 32,
|
||||
"code": 58893,
|
||||
"name": "icon-arrows-right-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 67,
|
||||
"order": 33,
|
||||
"id": 52,
|
||||
"prevSize": 32,
|
||||
"code": 53,
|
||||
"name": "icon-arrows-up-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 24,
|
||||
"order": 26,
|
||||
"id": 51,
|
||||
"prevSize": 32,
|
||||
"code": 42,
|
||||
"name": "icon-asterisk",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 25,
|
||||
"order": 27,
|
||||
"id": 50,
|
||||
"prevSize": 32,
|
||||
"code": 72,
|
||||
"name": "icon-autoflow-tabular",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 68,
|
||||
"order": 28,
|
||||
"id": 49,
|
||||
"prevSize": 32,
|
||||
"code": 224,
|
||||
"name": "icon-box-round-corners",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 69,
|
||||
"order": 29,
|
||||
"id": 48,
|
||||
"prevSize": 32,
|
||||
"code": 50,
|
||||
"name": "icon-check",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 26,
|
||||
"order": 30,
|
||||
"id": 47,
|
||||
"prevSize": 32,
|
||||
"code": 67,
|
||||
"name": "icon-clock",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 27,
|
||||
"order": 31,
|
||||
"id": 46,
|
||||
"prevSize": 32,
|
||||
"code": 46,
|
||||
"name": "icon-connectivity",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 28,
|
||||
"order": 32,
|
||||
"id": 45,
|
||||
"prevSize": 32,
|
||||
"code": 100,
|
||||
"name": "icon-database-query",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 29,
|
||||
"order": 17,
|
||||
"id": 44,
|
||||
"prevSize": 32,
|
||||
"code": 68,
|
||||
"name": "icon-database",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 30,
|
||||
"order": 35,
|
||||
"id": 43,
|
||||
"prevSize": 32,
|
||||
"code": 81,
|
||||
"name": "icon-dictionary",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 31,
|
||||
"order": 36,
|
||||
"id": 42,
|
||||
"prevSize": 32,
|
||||
"code": 242,
|
||||
"name": "icon-duplicate",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 32,
|
||||
"order": 37,
|
||||
"id": 41,
|
||||
"prevSize": 32,
|
||||
"code": 102,
|
||||
"name": "icon-folder-new",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 33,
|
||||
"order": 38,
|
||||
"id": 40,
|
||||
"prevSize": 32,
|
||||
"code": 70,
|
||||
"name": "icon-folder",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 34,
|
||||
"order": 39,
|
||||
"id": 39,
|
||||
"prevSize": 32,
|
||||
"code": 95,
|
||||
"name": "icon-fullscreen-collapse",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 35,
|
||||
"order": 40,
|
||||
"id": 38,
|
||||
"prevSize": 32,
|
||||
"code": 122,
|
||||
"name": "icon-fullscreen-expand",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 36,
|
||||
"order": 41,
|
||||
"id": 37,
|
||||
"prevSize": 32,
|
||||
"code": 71,
|
||||
"name": "icon-gear",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 39,
|
||||
"order": 49,
|
||||
"id": 34,
|
||||
"prevSize": 32,
|
||||
"code": 227,
|
||||
"name": "icon-image",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 70,
|
||||
"order": 42,
|
||||
"id": 33,
|
||||
"prevSize": 32,
|
||||
"code": 225,
|
||||
"name": "icon-layers",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 71,
|
||||
"order": 43,
|
||||
"id": 32,
|
||||
"prevSize": 32,
|
||||
"code": 76,
|
||||
"name": "icon-layout",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 40,
|
||||
"order": 44,
|
||||
"id": 31,
|
||||
"prevSize": 32,
|
||||
"code": 226,
|
||||
"name": "icon-line-horz",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 41,
|
||||
"order": 45,
|
||||
"id": 30,
|
||||
"prevSize": 32,
|
||||
"code": 244,
|
||||
"name": "icon-link",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 42,
|
||||
"order": 46,
|
||||
"id": 29,
|
||||
"prevSize": 32,
|
||||
"code": 88,
|
||||
"name": "icon-magnify-in",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 43,
|
||||
"order": 47,
|
||||
"id": 28,
|
||||
"prevSize": 32,
|
||||
"code": 89,
|
||||
"name": "icon-magnify-out",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 44,
|
||||
"order": 48,
|
||||
"id": 27,
|
||||
"prevSize": 32,
|
||||
"code": 77,
|
||||
"name": "icon-magnify",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 45,
|
||||
"order": 34,
|
||||
"id": 26,
|
||||
"prevSize": 32,
|
||||
"code": 109,
|
||||
"name": "icon-menu",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 46,
|
||||
"order": 50,
|
||||
"id": 25,
|
||||
"prevSize": 32,
|
||||
"code": 243,
|
||||
"name": "icon-move",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 47,
|
||||
"order": 51,
|
||||
"id": 24,
|
||||
"prevSize": 32,
|
||||
"code": 121,
|
||||
"name": "icon-new-window",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 48,
|
||||
"order": 52,
|
||||
"id": 23,
|
||||
"prevSize": 32,
|
||||
"code": 111,
|
||||
"name": "icon-object",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 49,
|
||||
"order": 53,
|
||||
"id": 22,
|
||||
"prevSize": 32,
|
||||
"code": 86,
|
||||
"name": "icon-packet",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 50,
|
||||
"order": 54,
|
||||
"id": 21,
|
||||
"prevSize": 32,
|
||||
"code": 234,
|
||||
"name": "icon-page",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 51,
|
||||
"order": 55,
|
||||
"id": 20,
|
||||
"prevSize": 32,
|
||||
"code": 241,
|
||||
"name": "icon-pause",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 52,
|
||||
"order": 56,
|
||||
"id": 19,
|
||||
"prevSize": 32,
|
||||
"code": 112,
|
||||
"name": "icon-pencil",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 87,
|
||||
"order": 65,
|
||||
"id": 18,
|
||||
"prevSize": 32,
|
||||
"code": 79,
|
||||
"name": "icon-people",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 102,
|
||||
"order": 57,
|
||||
"id": 17,
|
||||
"prevSize": 32,
|
||||
"code": 239,
|
||||
"name": "icon-play",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 103,
|
||||
"order": 58,
|
||||
"id": 16,
|
||||
"prevSize": 32,
|
||||
"code": 233,
|
||||
"name": "icon-plot-resource",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 105,
|
||||
"order": 59,
|
||||
"id": 15,
|
||||
"prevSize": 32,
|
||||
"code": 43,
|
||||
"name": "icon-plus",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 109,
|
||||
"order": 60,
|
||||
"id": 76,
|
||||
"prevSize": 32,
|
||||
"code": 45,
|
||||
"name": "icon-minus",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 61,
|
||||
"id": 11,
|
||||
"prevSize": 32,
|
||||
"code": 54,
|
||||
"name": "icon-sine",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 110,
|
||||
"order": 62,
|
||||
"id": 10,
|
||||
"prevSize": 32,
|
||||
"code": 228,
|
||||
"name": "icon-T",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 132,
|
||||
"order": 63,
|
||||
"id": 9,
|
||||
"prevSize": 32,
|
||||
"code": 116,
|
||||
"name": "icon-telemetry-panel",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 112,
|
||||
"order": 64,
|
||||
"id": 8,
|
||||
"prevSize": 32,
|
||||
"code": 84,
|
||||
"name": "icon-telemetry",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 113,
|
||||
"order": 18,
|
||||
"id": 7,
|
||||
"prevSize": 32,
|
||||
"code": 246,
|
||||
"name": "icon-thumbs-strip",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 114,
|
||||
"order": 67,
|
||||
"id": 6,
|
||||
"prevSize": 32,
|
||||
"code": 83,
|
||||
"name": "icon-timeline",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 104,
|
||||
"order": 68,
|
||||
"id": 5,
|
||||
"prevSize": 32,
|
||||
"code": 245,
|
||||
"name": "icon-timer",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 101,
|
||||
"order": 69,
|
||||
"id": 4,
|
||||
"prevSize": 32,
|
||||
"code": 90,
|
||||
"name": "icon-trash",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 86,
|
||||
"order": 70,
|
||||
"id": 3,
|
||||
"prevSize": 32,
|
||||
"code": 229,
|
||||
"name": "icon-two-parts-both",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 73,
|
||||
"order": 71,
|
||||
"id": 2,
|
||||
"prevSize": 32,
|
||||
"code": 231,
|
||||
"name": "icon-two-parts-one-only",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 116,
|
||||
"order": 72,
|
||||
"id": 1,
|
||||
"prevSize": 32,
|
||||
"code": 120,
|
||||
"name": "icon-x-heavy",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 0,
|
||||
"order": 66,
|
||||
"id": 0,
|
||||
"prevSize": 32,
|
||||
"code": 58946,
|
||||
@ -580,7 +588,7 @@
|
||||
"metadata": {
|
||||
"name": "Open MCT Web UI Symbols",
|
||||
"importSize": {
|
||||
"width": 256,
|
||||
"width": 512,
|
||||
"height": 512
|
||||
},
|
||||
"designer": "Charles Hacskaylo"
|
||||
@ -1131,8 +1139,8 @@
|
||||
{
|
||||
"id": 41,
|
||||
"paths": [
|
||||
"M894 188h-384v-64c0-70.4-57.6-128-128-128h-256c-70.4 0-128 57.6-128 128v320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v-128c0-70.4-57.6-128-128-128z",
|
||||
"M894 444h-768c-70.4 0-128 57.6-128 128v320c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-320c0-70.4-57.6-128-128-128zM702 764h-128v128h-128v-128h-128v-128h128v-128h128v128h128v128z"
|
||||
"M896 192h-320c-16.4-16.4-96.8-96.8-109.2-109.2l-37.4-37.4c-25-25-74.2-45.4-109.4-45.4h-256c-35.2 0-64 28.8-64 64v384c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v-128c0-70.4-57.6-128-128-128z",
|
||||
"M896 448h-768c-70.4 0-128 57.6-128 128v320c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-320c0-70.4-57.6-128-128-128zM704 800h-128v128h-128v-128h-128v-128h128v-128h128v128h128v128z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
@ -1147,8 +1155,8 @@
|
||||
{
|
||||
"id": 40,
|
||||
"paths": [
|
||||
"M896 190h-384v-64c0-70.4-57.6-128-128-128h-256c-70.4 0-128 57.6-128 128v320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v-128c0-70.4-57.6-128-128-128z",
|
||||
"M896 446h-768c-70.4 0-128 57.6-128 128v320c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-320c0-70.4-57.6-128-128-128z"
|
||||
"M896 192h-320c-16.4-16.4-96.8-96.8-109.2-109.2l-37.4-37.4c-25-25-74.2-45.4-109.4-45.4h-256c-35.2 0-64 28.8-64 64v384c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v-128c0-70.4-57.6-128-128-128z",
|
||||
"M896 448h-768c-70.4 0-128 57.6-128 128v320c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-320c0-70.4-57.6-128-128-128z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
@ -1526,6 +1534,20 @@
|
||||
"icon-plus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 76,
|
||||
"paths": [
|
||||
"M960 640c35.2 0 64-28.8 64-64v-128c0-35.2-28.8-64-64-64h-896c-35.2 0-64 28.8-64 64v128c0 35.2 28.8 64 64 64h896z"
|
||||
],
|
||||
"attrs": [
|
||||
{}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-minus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"paths": [
|
||||
|
Binary file not shown.
@ -10,6 +10,7 @@
|
||||
<glyph unicode="!" d="M832 960h-640c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM640 128c0-35.2-28.8-64-64-64h-128c-35.2 0-64 28.8-64 64v64c0 35.2 28.8 64 64 64h128c35.2 0 64-28.8 64-64v-64zM696.062 768.494l-48.124-384.988c-4.366-34.928-36.738-63.506-71.938-63.506h-128c-35.2 0-67.572 28.578-71.938 63.506l-48.124 384.988c-4.366 34.928 20.862 63.506 56.062 63.506h256c35.2 0 60.428-28.578 56.062-63.506z" />
|
||||
<glyph unicode="*" d="M1004.166 619.542l-97.522 168.916-330.534-229.414 33.414 400.956h-195.048l33.414-400.956-330.534 229.414-97.522-168.916 363.944-171.542-363.944-171.542 97.522-168.916 330.534 229.414-33.414-400.956h195.048l-33.414 400.956 330.534-229.414 97.522 168.916-363.944 171.542z" />
|
||||
<glyph unicode="+" d="M960 576h-330v320c0 35.2-28.8 64-64 64h-108c-35.2 0-64-28.8-64-64v-320h-330c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h330v-320c0-35.2 28.8-64 64-64h108c35.2 0 64 28.8 64 64v320h330c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64z" />
|
||||
<glyph unicode="-" d="M960 320c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64h-896c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h896z" />
|
||||
<glyph unicode="." d="M704 384c0-70.4-57.6-128-128-128h-128c-70.4 0-128 57.6-128 128v128c0 70.4 57.6 128 128 128h128c70.4 0 128-57.6 128-128v-128zM1024 448l-192 320v-640zM0 448l192 320v-640z" />
|
||||
<glyph unicode="2" d="M1024 960l-640-640-384 384v-384l384-384 640 640z" />
|
||||
<glyph unicode="3" d="M640 704h-256c-70.4 0-128-57.6-128-128v-256c0-70.4 57.6-128 128-128h256c70.4 0 128 57.6 128 128v256c0 70.4-57.6 128-128 128zM0 960h192v-192h-192v192zM256 960h192v-128h-192v128zM576 960h192v-128h-192v128zM256 64h192v-128h-192v128zM576 64h192v-128h-192v128zM0 384h128v-192h-128v192zM0 704h128v-192h-128v192zM896 384h128v-192h-128v192zM896 704h128v-192h-128v192zM832 960h192v-192h-192v192zM0 128h192v-192h-192v192zM832 128h192v-192h-192v192z" />
|
||||
@ -20,7 +21,7 @@
|
||||
<glyph unicode="A" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
|
||||
<glyph unicode="C" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM768 384h-256c-35.2 0-64 28.8-64 64v384c0 35.2 28.8 64 64 64s64-28.8 64-64v-320h192c35.2 0 64-28.8 64-64s-28.8-64-64-64z" />
|
||||
<glyph unicode="D" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.77 0-512 85.962-512 192v-512c0-106.038 229.23-192 512-192s512 85.962 512 192v512c0-106.038-229.23-192-512-192z" />
|
||||
<glyph unicode="F" d="M896 770h-384v64c0 70.4-57.6 128-128 128h-256c-70.4 0-128-57.6-128-128v-320c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 514h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128z" />
|
||||
<glyph unicode="F" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128z" />
|
||||
<glyph unicode="G" d="M1024 384v128l-140.976 35.244c-8.784 32.922-21.818 64.106-38.504 92.918l74.774 124.622-90.51 90.51-124.622-74.774c-28.812 16.686-59.996 29.72-92.918 38.504l-35.244 140.976h-128l-35.244-140.976c-32.922-8.784-64.106-21.818-92.918-38.504l-124.622 74.774-90.51-90.51 74.774-124.622c-16.686-28.812-29.72-59.996-38.504-92.918l-140.976-35.244v-128l140.976-35.244c8.784-32.922 21.818-64.106 38.504-92.918l-74.774-124.622 90.51-90.51 124.622 74.774c28.812-16.686 59.996-29.72 92.918-38.504l35.244-140.976h128l35.244 140.976c32.922 8.784 64.106 21.818 92.918 38.504l124.622-74.774 90.51 90.51-74.774 124.622c16.686 28.812 29.72 59.996 38.504 92.918l140.976 35.244zM704 448c0-106.038-85.962-192-192-192s-192 85.962-192 192 85.962 192 192 192 192-85.962 192-192z" />
|
||||
<glyph unicode="H" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
||||
<glyph unicode="I" d="M0 448l256-256v512zM512 960l-256-256h512zM512-64l256 256h-512zM768 704v-512l256 256z" />
|
||||
@ -39,7 +40,7 @@
|
||||
<glyph unicode="_" d="M191.656 128c0.118-0.1 0.244-0.224 0.344-0.344v-191.656h192v192c0 105.6-86.4 192-192 192h-192v-192h191.656zM192 768.344c-0.1-0.118-0.224-0.244-0.344-0.344h-191.656v-192h192c105.6 0 192 86.4 192 192v192h-192v-191.656zM832 576h192v192h-191.656c-0.118 0.1-0.244 0.226-0.344 0.344v191.656h-192v-192c0-105.6 86.4-192 192-192zM832 127.656c0.1 0.118 0.224 0.244 0.344 0.344h191.656v192h-192c-105.6 0-192-86.4-192-192v-192h192v191.656z" />
|
||||
<glyph unicode="a" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
||||
<glyph unicode="d" d="M683.52 140.714c-50.782-28.456-109.284-44.714-171.52-44.714-194.094 0-352 157.906-352 352s157.906 352 352 352 352-157.906 352-352c0-62.236-16.258-120.738-44.714-171.52l191.692-191.692c8.516 13.89 13.022 28.354 13.022 43.212v640c0 106.038-229.23 192-512 192s-512-85.962-512-192v-640c0-106.038 229.23-192 512-192 126.11 0 241.548 17.108 330.776 45.46l-159.256 159.254zM352 448c0-88.224 71.776-160 160-160s160 71.776 160 160-71.776 160-160 160-160-71.776-160-160z" />
|
||||
<glyph unicode="f" d="M894 772h-384v64c0 70.4-57.6 128-128 128h-256c-70.4 0-128-57.6-128-128v-320c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM894 516h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128zM702 196h-128v-128h-128v128h-128v128h128v128h128v-128h128v-128z" />
|
||||
<glyph unicode="f" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128zM704 160h-128v-128h-128v128h-128v128h128v128h128v-128h128v-128z" />
|
||||
<glyph unicode="l" d="M832 576h-32v96c0 158.8-129.2 288-288 288s-288-129.2-288-288v-96h-32c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h640c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128zM416 672c0 53 43 96 96 96s96-43 96-96v-96h-192v96z" />
|
||||
<glyph unicode="m" d="M0 960h1024v-256h-1024v256zM0 576h1024v-256h-1024v256zM0 192h1024v-256h-1024v256z" />
|
||||
<glyph unicode="o" d="M512-64l512 320v384l-512.020 320-511.98-320v-384l512-320zM512 768l358.4-224-358.4-224-358.4 224 358.4 224z" />
|
||||
@ -74,5 +75,8 @@
|
||||
<glyph unicode="ô" d="M832 960h-640c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM832 320l-128 128-512-320 320 512-128 128h448v-448z" />
|
||||
<glyph unicode="õ" d="M638 898c0 35.4-28.6 64-64 64h-128c-35.4 0-64-28.6-64-64s28.6-64 64-64h128c35.4 0 64 28.6 64 64zM510 834c-247.4 0-448-200.6-448-448s200.6-448 448-448 448 200.6 448 448-200.6 448-448 448zM510 386h-336c0 185.2 150.8 336 336 336v-336z" />
|
||||
<glyph unicode="ö" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
|
||||
<glyph unicode="" d="M832 447.6c0 0.2 0 0.2 0 0.4v320c0 105.6-86.4 192-192 192h-448c-105.6 0-192-86.4-192-192v-320c0-105.6 86.4-192 192-192h263.6l-197.2 445.6 573.6-254zM766.8 300.2l193.8 20.4-576.6 255.4 255.4-576.6 20.4 193.8 257-257.2 107.2 107.2z" />
|
||||
<glyph unicode="" d="M998.208 111.136l-422.702 739.728c-34.928 61.124-92.084 61.124-127.012 0l-422.702-739.728c-34.928-61.126-5.906-111.136 64.494-111.136h843.428c70.4 0 99.422 50.010 64.494 111.136zM512 128c-35.2 0-64 28.8-64 64s28.8 64 64 64 64-28.8 64-64c0-35.2-28.8-64-64-64zM627.448 577.242l-38.898-194.486c-6.902-34.516-41.35-62.756-76.55-62.756s-69.648 28.24-76.552 62.758l-38.898 194.486c-6.902 34.516 16.25 62.756 51.45 62.756h128c35.2 0 58.352-28.24 51.448-62.758z" />
|
||||
<glyph unicode="" d="M1024 448l-448-512v1024zM448 960l-448-512 448-512z" />
|
||||
<glyph unicode="" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
|
||||
</font></defs></svg>
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Binary file not shown.
@ -20,10 +20,10 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
// Features
|
||||
/************************** FEATURES */
|
||||
$enableImageryThumbs: false; // Set to true if historical imagery thumbnails are supported
|
||||
|
||||
// Margins, spacing, radii
|
||||
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
|
||||
$bodyMargin: 10px;
|
||||
$interiorMargin: 5px;
|
||||
$interiorMarginLg: $interiorMargin * 2;
|
||||
@ -33,7 +33,7 @@ $controlCr: 2px;
|
||||
$smallCr: 2px;
|
||||
$badgeW: 35px;
|
||||
|
||||
// Colors and shading
|
||||
/************************** COLORS AND SHADING */
|
||||
$colorBodyBg: #333;
|
||||
$colorBodyFg: #999;
|
||||
$colorFooterBg: #000;
|
||||
@ -44,64 +44,68 @@ $colorAlt1: #ffc700;
|
||||
$colorAlert: #ff3c00;
|
||||
$colorPausedBg: #c56f01;
|
||||
$colorPausedFg: #fff;
|
||||
$colorCheck: $colorKey;
|
||||
$colorCreateBtn: $colorKey;
|
||||
$colorGridLines: rgba(#fff, 0.05);
|
||||
// Menu colors
|
||||
$colorMenuBg: lighten($colorBodyBg, 23%);
|
||||
$colorMenuFg: lighten($colorMenuBg, 70%);
|
||||
$colorMenuIc: lighten($colorKey, 17%);
|
||||
$colorInteriorBorder: lighten($colorBodyBg, 10%);
|
||||
$colorObjFrameBg: darken($colorBodyBg, 5%);
|
||||
// Form colors
|
||||
$colorCheck: $colorKey;
|
||||
$colorFormRequired: #ffc700;
|
||||
$colorFormValid: #33cc33;
|
||||
$colorFormError: #cc0000;
|
||||
$colorFormInvalid: #ff9900;
|
||||
$colorGridLines: rgba(#fff, 0.05);
|
||||
// Limits and staleness colors
|
||||
$colorLimitYellow: #9d7500;
|
||||
$colorLimitRed: #aa0000;
|
||||
$colorTelemFresh: #fff;
|
||||
$colorTelemStale: #888;
|
||||
$styleTelemStale: italic;
|
||||
// Bubble colors
|
||||
$colorInfoBubbleFg: #666;
|
||||
$colorInfoBubbleBg: #ddd;
|
||||
$colorThumbsBubbleFg: lighten($colorBodyFg, 10%);
|
||||
$colorThumbsBubbleBg: lighten($colorBodyBg, 10%);
|
||||
$colorLimitYellow: #9d7500;
|
||||
$colorLimitRed: #aa0000;
|
||||
$colorTelemFresh: #fff;
|
||||
$colorTelemStale: #888;
|
||||
$styleTelemState: italic;
|
||||
$colorInfoBubbleFg: #666;
|
||||
$colorInfoBubbleBg: #ddd;
|
||||
|
||||
// Ratios
|
||||
$ltGamma: 20%;
|
||||
$btnFontSizeToH: 0.45;
|
||||
|
||||
// User Environment
|
||||
$ueTopBarH: 24px; // Change to when breadcrumb is enabled
|
||||
$ueTopBarEditH: 30px;
|
||||
$ueTopBarBtnH: 35px;
|
||||
$ueFooterH: 20px;
|
||||
$ueColMargin: 1.5%;
|
||||
$ueAppLogoW: 105px;
|
||||
//$ueBrowseViewBarH: $ueTopBarH; // was 30px
|
||||
$ueEditToolBarH: 25px;
|
||||
$ueBrowseLeftPaneW: 25%;
|
||||
$ueEditLeftPaneW: 75%;
|
||||
|
||||
// Overlay
|
||||
$colorOvrBlocker: rgba(black, 0.7);
|
||||
$colorOvrBg: $colorBodyBg;
|
||||
$colorOvrFg: $colorBodyFg;
|
||||
$ovrTopBarH: 60px;
|
||||
$ovrFooterH: 40px;
|
||||
|
||||
//Items
|
||||
$ueBrowseGridItemLg: 200px;
|
||||
$ueBrowseGridItemTopBarH: 20px;
|
||||
$ueBrowseGridItemBottomBarH: 30px;
|
||||
// Items
|
||||
$colorItemBase: lighten($colorBodyBg, 5%);
|
||||
$colorItemFg: lighten($colorItemBase, 20%);
|
||||
$colorItemSelected: $colorKey;
|
||||
$itemPadLR: 5px;
|
||||
// Tabular
|
||||
$tabularColorBorder: rgba(white, 0.1);
|
||||
$tabularColorBodyBg: darken($colorBodyBg, 10%);
|
||||
$tabularColorBodyFg: lighten($tabularColorBodyBg, 40%);
|
||||
$tabularColorHeaderBg: lighten($colorBodyBg, 10%);
|
||||
$tabularColorHeaderFg: lighten($tabularColorHeaderBg, 40%);
|
||||
|
||||
/************************** RATIOS */
|
||||
$ltGamma: 20%;
|
||||
$btnFontSizeToH: 0.45;
|
||||
|
||||
/************************** LAYOUT */
|
||||
$ueTopBarH: 24px; // Change when breadcrumb is enabled
|
||||
$ueTopBarEditH: 30px;
|
||||
$ueTopBarBtnH: 35px;
|
||||
$ueFooterH: 25px;
|
||||
$ueColMargin: 1.5%;
|
||||
$ueAppLogoW: 105px;
|
||||
$ueEditToolBarH: 25px;
|
||||
$ueBrowseLeftPaneW: 25%;
|
||||
$ueEditLeftPaneW: 75%;
|
||||
// Overlay
|
||||
$ovrTopBarH: 60px;
|
||||
$ovrFooterH: 40px;
|
||||
// Items
|
||||
$ueBrowseGridItemLg: 200px;
|
||||
$ueBrowseGridItemTopBarH: 20px;
|
||||
$ueBrowseGridItemBottomBarH: 30px;
|
||||
$itemPadLR: 5px;
|
||||
// Tree
|
||||
$treeVCW: 10px;
|
||||
$treeTypeIconW: 20px;
|
||||
@ -109,18 +113,33 @@ $treeContextTriggerW: 20px;
|
||||
$colorItemTreeIcon: $colorKey;
|
||||
$colorItemTreeIconHover: lighten($colorItemTreeIcon, 20%);
|
||||
$colorItemTreeVCHover: $colorAlt1;
|
||||
|
||||
//Tabular
|
||||
// Tabular
|
||||
$tabularHeaderH: 18px;
|
||||
$tabularTdPadLR: $itemPadLR;
|
||||
$tabularTdPadTB: 2px;
|
||||
$tabularColorBorder: rgba(white, 0.1);
|
||||
$tabularColorBodyBg: darken($colorBodyBg, 10%);
|
||||
$tabularColorBodyFg: lighten($tabularColorBodyBg, 40%);
|
||||
$tabularColorHeaderBg: lighten($colorBodyBg, 10%);
|
||||
$tabularColorHeaderFg: lighten($tabularColorHeaderBg, 40%);
|
||||
// Imagery
|
||||
$imageMainControlBarH: 20px;
|
||||
$imageThumbsD: 120px;
|
||||
$imageThumbsWrapperH: $imageThumbsD * 1.4;
|
||||
$imageThumbPad: 1px;
|
||||
// Ticks
|
||||
$ticksH: 25px;
|
||||
$tickLblVMargin: 3px;
|
||||
$tickLblH: 15px;
|
||||
$tickLblW: 50px;
|
||||
$tickH: $ticksH - $tickLblVMargin - $tickLblH;
|
||||
$tickW: 1px;
|
||||
// Bubbles
|
||||
$bubbleArwSize: 10px;
|
||||
$bubblePad: $interiorMargin;
|
||||
$bubbleMinW: 100px;
|
||||
$bubbleMaxW: 300px;
|
||||
// Forms
|
||||
$reqSymbolW: 15px;
|
||||
$reqSymbolM: $interiorMargin * 2;
|
||||
$reqSymbolFontSize: 0.7em;
|
||||
|
||||
// Controls
|
||||
/************************** CONTROLS */
|
||||
$controlCr: $basicCr;
|
||||
$controlDisabledOpacity: 0.3;
|
||||
$formLabelW: 20%;
|
||||
@ -132,34 +151,9 @@ $scrollbarTrackColorBg: rgba(#000, 0.4);
|
||||
$btnStdH: 25px;
|
||||
$btnToolbarH: $btnStdH;
|
||||
|
||||
// Paths
|
||||
/************************** PATHS */
|
||||
$dirImgs: '../images/'; // Relative to platform/css/ directory
|
||||
|
||||
// Ticks
|
||||
$ticksH: 25px;
|
||||
$tickLblVMargin: 3px;
|
||||
$tickLblH: 15px;
|
||||
$tickLblW: 50px;
|
||||
$tickH: $ticksH - $tickLblVMargin - $tickLblH;
|
||||
$tickW: 1px;
|
||||
|
||||
// Imagery
|
||||
$imageMainControlBarH: 20px;
|
||||
$imageThumbsD: 120px;
|
||||
$imageThumbsWrapperH: $imageThumbsD * 1.4;
|
||||
$imageThumbPad: 1px;
|
||||
|
||||
// Bubbles
|
||||
$bubbleArwSize: 10px;
|
||||
$bubblePad: $interiorMargin;
|
||||
$bubbleMinW: 100px;
|
||||
$bubbleMaxW: 300px;
|
||||
|
||||
|
||||
// Timing
|
||||
/************************** TIMINGS */
|
||||
$controlFadeMs: 100ms;
|
||||
|
||||
// Forms
|
||||
$reqSymbolW: 15px;
|
||||
$reqSymbolM: $interiorMargin * 2;
|
||||
$reqSymbolFontSize: 0.7em;
|
@ -29,10 +29,13 @@ a {
|
||||
}
|
||||
|
||||
body, html {
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-color: $colorBodyBg;
|
||||
color: $colorBodyFg;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 100%;
|
||||
//font-weight: 500;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
.browse-area.holder {
|
||||
// When .browse.top-bar is hidden, set the top of the browse-area holder
|
||||
top: $interiorMargin;
|
||||
top: $bodyMargin;
|
||||
> .contents.split-layout {
|
||||
// Don't pad in from top and bottom
|
||||
//top: 0; bottom: 0;
|
||||
|
@ -174,10 +174,11 @@
|
||||
|
||||
@mixin controlGrippy($b, $direction: horizontal, $w: 1px, $style: dotted) {
|
||||
&:before {
|
||||
// Grippy
|
||||
@include trans-prop-nice("border-color",0.75s);
|
||||
content: '';
|
||||
display: block;
|
||||
height: auto;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
||||
@ -195,7 +196,8 @@
|
||||
}
|
||||
}
|
||||
&:not(.disabled):hover:before {
|
||||
border-color: rgba($colorKey, 0.9);
|
||||
@include trans-prop-nice("border-color",50ms);
|
||||
border-color: $colorKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ $pad: $interiorMargin * $baseRatio;
|
||||
/******* LAYOUT AND SIZING */
|
||||
.btn,
|
||||
.l-btn {
|
||||
@include user-select(none);
|
||||
line-height: 1.5em; // Was 1.25em
|
||||
padding: 0 $pad;
|
||||
text-decoration: none;
|
||||
|
@ -37,7 +37,6 @@
|
||||
ul {
|
||||
@include menuUlReset();
|
||||
li {
|
||||
// @include border-radius($controlCr);
|
||||
@include box-sizing(border-box);
|
||||
border-top: 1px solid lighten($bg, 20%);
|
||||
line-height: $menuLineH;
|
||||
@ -65,20 +64,39 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu,
|
||||
.super-menu {
|
||||
$bg: $colorMenuBg;
|
||||
$fg: $colorMenuFg;
|
||||
$ic: $colorMenuIc;
|
||||
//font-size: 0.80rem;
|
||||
pointer-events: auto;
|
||||
@include containerSubtle($bg);
|
||||
ul li {
|
||||
padding-left: 25px;
|
||||
a { color: $fg; }
|
||||
.icon {
|
||||
color: $ic;
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin;
|
||||
}
|
||||
&:hover .icon {
|
||||
color: lighten($ic, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.super-menu {
|
||||
$w: 450px;
|
||||
$w: 500px;
|
||||
$h: $w - 20;
|
||||
$plw: 50%; //$w * 0.5;
|
||||
$prw: 50%; //$w - $plw;
|
||||
$bg: $colorKey;
|
||||
$fg: $colorKeyFg;
|
||||
$colorMid: lighten($bg, 25%);
|
||||
$bgHover: $bg;
|
||||
@include containerSubtle(darken($bg, 15%), $fg);
|
||||
$fg: #fff; //lighten($colorBodyFg, 40%);
|
||||
$bgHover: $colorKey; //$bg;
|
||||
display: block;
|
||||
.icon {
|
||||
color: $colorMid;
|
||||
}
|
||||
width: $w;
|
||||
height: $h;
|
||||
.contents {
|
||||
@ -98,21 +116,8 @@
|
||||
ul {
|
||||
li {
|
||||
@include border-radius($controlCr);
|
||||
// @include test(red);
|
||||
padding-left: 30px;
|
||||
border-top: none;
|
||||
color: $fg;
|
||||
// font-size: 0.85em;
|
||||
// line-height: 20px;
|
||||
&:hover {
|
||||
background: $bgHover;
|
||||
.icon {
|
||||
color: lighten($bg, 50%);
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
@include txtShdwSubtle(0.4);
|
||||
left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,13 +127,14 @@
|
||||
right: 0;
|
||||
padding: $interiorMargin * 5;
|
||||
width: $prw;
|
||||
.icon {
|
||||
color: $fg;
|
||||
}
|
||||
}
|
||||
}
|
||||
.menu-item-description {
|
||||
.desc-area {
|
||||
// @include test(green);
|
||||
&.icon {
|
||||
//@include test(red);
|
||||
$h: 150px;
|
||||
position: relative;
|
||||
font-size: 8em;
|
||||
@ -153,27 +159,7 @@
|
||||
}
|
||||
}
|
||||
.context-menu {
|
||||
$bg: lighten($colorBodyBg, 25%);
|
||||
$fg: lighten($bg, 70%);
|
||||
$ic: lighten($colorKey, 15%);
|
||||
font-size: 0.80rem;
|
||||
pointer-events: auto;
|
||||
&.menu {
|
||||
@include containerSubtle($bg);
|
||||
ul li {
|
||||
padding-left: 30px;
|
||||
a { color: $fg; }
|
||||
.icon {
|
||||
color: $ic;
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin;
|
||||
}
|
||||
&:hover .icon {
|
||||
color: lighten($ic, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@
|
||||
}
|
||||
|
||||
.l-image-main {
|
||||
cursor: crosshair;
|
||||
//cursor: crosshair;
|
||||
}
|
||||
|
||||
.l-image-main-controlbar {
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Layout
|
||||
&:hover {
|
||||
.l-btn.control {
|
||||
//display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@ -20,6 +19,9 @@
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
.ui-symbol.direction {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
&:hover .l-elem.l-value {
|
||||
left: 20px;
|
||||
@ -35,10 +37,10 @@
|
||||
}
|
||||
.l-btn.control {
|
||||
@include trans-prop-nice-fade($transTime);
|
||||
//display: none;
|
||||
opacity: 0;
|
||||
font-size: 0.9em;
|
||||
line-height: 1em;
|
||||
font-size: 0.65em;
|
||||
vertical-align: top;
|
||||
//line-height: 1em;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,18 +30,18 @@
|
||||
border-collapse: collapse;
|
||||
color: #fff;
|
||||
display: table;
|
||||
font-size: 0.8em;
|
||||
font-size: 0.75em;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
//height: 100%; MOVED
|
||||
width: 100%;
|
||||
thead, .thead,
|
||||
tbody tr, .tbody .tr {
|
||||
display: table;
|
||||
//display: table; MOVED
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
//table-layout: fixed; MOVED
|
||||
}
|
||||
thead, .thead {
|
||||
width: calc(100% - 10px);
|
||||
//width: calc(100% - 10px); MOVED
|
||||
tr, .tr {
|
||||
height: $tabularHeaderH;
|
||||
}
|
||||
@ -56,12 +56,11 @@
|
||||
}
|
||||
}
|
||||
tbody, .tbody {
|
||||
@include absPosDefault(0);
|
||||
top: $tabularHeaderH;
|
||||
//display: table-row-group;
|
||||
display: block;
|
||||
//width: 100%;
|
||||
overflow-y: scroll;
|
||||
//@include absPosDefault(0); MOVED
|
||||
//top: $tabularHeaderH; MOVED
|
||||
//display: block; MOVED
|
||||
//overflow-y: scroll; MOVED
|
||||
display: table-row-group;
|
||||
tr, .tr {
|
||||
&:hover {
|
||||
background: rgba(white, 0.1);
|
||||
@ -69,8 +68,7 @@
|
||||
}
|
||||
}
|
||||
tr, .tr {
|
||||
//display: table-row;
|
||||
//width: 100%;
|
||||
display: table-row;
|
||||
&:first-child .td {
|
||||
border-top: none;
|
||||
}
|
||||
@ -100,30 +98,13 @@
|
||||
content: '1';
|
||||
}
|
||||
}
|
||||
/* em {
|
||||
//background: rgba(green, 0.2);
|
||||
border-left: 1px solid $tabularColorBorder;
|
||||
color: $tabularColorHeaderFg;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
height: $tabularHeaderH;
|
||||
line-height: $tabularHeaderH;
|
||||
margin-left: - $tabularTdPadLR;
|
||||
padding: 0 $tabularTdPadLR;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
vertical-align: middle;
|
||||
&:hover {
|
||||
color: lighten($tabularColorHeaderFg, 20%);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
td, .td {
|
||||
border-top: 1px solid $tabularColorBorder;
|
||||
min-width: 110px;
|
||||
color: $colorTelemFresh;
|
||||
padding: $tabularTdPadTB $tabularTdPadLR;
|
||||
vertical-align: top;
|
||||
&.numeric {
|
||||
text-align: right;
|
||||
}
|
||||
@ -142,4 +123,27 @@
|
||||
top: $tabularHeaderH * 2;
|
||||
}
|
||||
}
|
||||
|
||||
&.fixed-header {
|
||||
height: 100%;
|
||||
thead, .thead,
|
||||
tbody tr, .tbody .tr {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
}
|
||||
thead, .thead {
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
tbody, .tbody {
|
||||
@include absPosDefault(0);
|
||||
top: $tabularHeaderH;
|
||||
display: block;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
&.t-event-messages {
|
||||
td, .td {
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
@ -65,7 +65,8 @@
|
||||
|
||||
.bottom-bar {
|
||||
top: auto; right: 0; bottom: 0; left: 0;
|
||||
font-size: 1em;
|
||||
overflow: visible;
|
||||
//font-size: 1em;
|
||||
height: $ovrFooterH;
|
||||
text-align: right;
|
||||
.btn {
|
||||
|
@ -19,5 +19,4 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* CONSTANTS */
|
||||
$bodyMargin: 5px;
|
||||
/* CONSTANTS */
|
@ -20,24 +20,31 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.ue-bottom-bar {
|
||||
background: $colorFooterBg;
|
||||
color: lighten($colorBodyBg, 30%);
|
||||
font-size: 0.65rem;
|
||||
line-height: $ueFooterH - 4px;
|
||||
font-size: .7rem;
|
||||
//line-height: $ueFooterH - 4px;
|
||||
//line-height: $ueFooterH; // New status bar design
|
||||
.status-holder {
|
||||
@include border-radius($basicCr * 1.75);
|
||||
//@include border-radius($basicCr * 1.75); // New status bar design
|
||||
@include box-sizing(border-box);
|
||||
background: $colorFooterBg;
|
||||
border-bottom: 1px solid lighten($colorBodyBg, 10%);
|
||||
padding: 2px 5px;
|
||||
//background: $colorFooterBg;
|
||||
//border-bottom: 1px solid lighten($colorBodyBg, 10%); // New status bar design
|
||||
@include absPosDefault($interiorMargin);
|
||||
@include ellipsize();
|
||||
line-height: $ueFooterH - ($interiorMargin * 2);
|
||||
right: 120px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.app-logo {
|
||||
@include box-sizing(border-box);
|
||||
@include absPosDefault($interiorMargin);
|
||||
left: auto;
|
||||
cursor: pointer;
|
||||
font-size: 0.8em;
|
||||
line-height: $ueFooterH - 10px;
|
||||
padding-top: 1px;
|
||||
text-transform: uppercase;
|
||||
//font-size: 0.8em;
|
||||
//line-height: $ueFooterH - 10px;
|
||||
//padding-top: 1px;
|
||||
//text-transform: uppercase;
|
||||
&.logo-openmctweb {
|
||||
background: url($dirImgs + 'logo-openmctweb.svg') no-repeat center center;
|
||||
}
|
||||
@ -45,16 +52,16 @@
|
||||
}
|
||||
|
||||
.status.block {
|
||||
display: inline-block;
|
||||
margin-right: $interiorMargin * 4;
|
||||
//display: inline-block;
|
||||
display: inline; // New status bar design. Inline to support ellipsis overflow
|
||||
margin-right: $interiorMargin * 2;
|
||||
.status-indicator {
|
||||
@include border-radius($controlCr * 0.9);
|
||||
@include box-shadow(inset rgba(black, 0.5) 0 0 3px);
|
||||
@include text-shadow(rgba(black, 0.3) 0 0 2px);
|
||||
//@include border-radius($controlCr * 0.9);
|
||||
//@include box-shadow(inset rgba(black, 0.5) 0 0 3px);
|
||||
//@include text-shadow(rgba(black, 0.3) 0 0 2px);
|
||||
display: inline-block;
|
||||
//font-size: 1.25em; // Normalized for new wtdsymbols font v2
|
||||
//vertical-align: middle; // Normalized for new wtdsymbols font v2
|
||||
margin-right: $interiorMarginSm;
|
||||
color: $colorKey;
|
||||
&.ok {
|
||||
color: #009900;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
.holder-all {
|
||||
$myM: $interiorMarginSm;
|
||||
$myM: 0; // $interiorMarginSm;
|
||||
top: $myM;
|
||||
right: $myM;
|
||||
bottom: $myM;
|
||||
@ -93,7 +93,7 @@
|
||||
.editor {
|
||||
top: $bodyMargin + $ueTopBarH + ($interiorMargin);
|
||||
right: $bodyMargin;
|
||||
bottom: $bodyMargin + $ueFooterH + $interiorMargin;
|
||||
bottom: $ueFooterH + $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
}
|
||||
|
||||
@ -119,15 +119,18 @@
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
@include absPosDefault($bodyMargin);
|
||||
//@include absPosDefault($bodyMargin);
|
||||
@include absPosDefault(0);// New status bar design
|
||||
top: auto;
|
||||
height: $ueFooterH;
|
||||
.status-holder {
|
||||
right: $ueAppLogoW + $bodyMargin;
|
||||
//right: $ueAppLogoW + $bodyMargin; New status bar design
|
||||
z-index: 1;
|
||||
}
|
||||
.app-logo {
|
||||
left: auto;
|
||||
width: $ueAppLogoW;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class='abs bottom-bar ue-bottom-bar' ng-controller="BottomBarController as bar">
|
||||
<div id='status' class='status-holder abs'>
|
||||
<div id='status' class='status-holder'>
|
||||
<mct-include ng-repeat="indicator in bar.getIndicators()"
|
||||
ng-model="indicator.ngModel"
|
||||
key="indicator.template">
|
||||
|
@ -57,13 +57,17 @@ define(
|
||||
// mouse may leave this element during the drag.
|
||||
var body = $document.find('body'),
|
||||
initialPosition,
|
||||
$event,
|
||||
delta;
|
||||
|
||||
// Utility function to cause evaluation of mctDrag,
|
||||
// mctDragUp, etc
|
||||
function fireListener(name) {
|
||||
// Evaluate the expression, with current delta
|
||||
scope.$eval(attrs[name], { delta: delta });
|
||||
scope.$eval(attrs[name], {
|
||||
delta: delta,
|
||||
$event: $event
|
||||
});
|
||||
|
||||
// Trigger prompt digestion
|
||||
scope.$apply();
|
||||
@ -82,6 +86,9 @@ define(
|
||||
delta = currentPosition.map(function (v, i) {
|
||||
return v - initialPosition[i];
|
||||
});
|
||||
|
||||
// Also track the plain event for firing listeners
|
||||
$event = event;
|
||||
}
|
||||
|
||||
// Called during a drag, on mousemove
|
||||
@ -106,7 +113,7 @@ define(
|
||||
|
||||
fireListener("mctDragUp");
|
||||
|
||||
// Clear out start-of-drag position
|
||||
// Clear out start-of-drag position, target
|
||||
initialPosition = undefined;
|
||||
|
||||
// Don't show selection highlights, etc
|
||||
@ -131,6 +138,7 @@ define(
|
||||
|
||||
// Don't show selection highlights, etc
|
||||
event.preventDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -148,4 +156,4 @@ define(
|
||||
|
||||
return MCTDrag;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
215
platform/commonUI/general/src/directives/MCTSplitPane.js
Normal file
215
platform/commonUI/general/src/directives/MCTSplitPane.js
Normal file
@ -0,0 +1,215 @@
|
||||
/*****************************************************************************
|
||||
* 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';
|
||||
|
||||
// Pixel width to allocate for the splitter itself
|
||||
var DEFAULT_ANCHOR = 'left',
|
||||
CHILDREN_WARNING_MESSAGE = [
|
||||
"Invalid mct-split-pane contents.",
|
||||
"This element should contain exactly three",
|
||||
"child elements, where the middle-most element",
|
||||
"is an mct-splitter."
|
||||
].join(" "),
|
||||
ANCHOR_WARNING_MESSAGE = [
|
||||
"Unknown anchor provided to mct-split-pane,",
|
||||
"defaulting to",
|
||||
DEFAULT_ANCHOR + "."
|
||||
].join(" "),
|
||||
ANCHORS = {
|
||||
left: {
|
||||
edge: "left",
|
||||
opposite: "right",
|
||||
dimension: "width",
|
||||
orientation: "vertical"
|
||||
},
|
||||
right: {
|
||||
edge: "right",
|
||||
opposite: "left",
|
||||
dimension: "width",
|
||||
orientation: "vertical",
|
||||
reversed: true
|
||||
},
|
||||
top: {
|
||||
edge: "top",
|
||||
opposite: "bottom",
|
||||
dimension: "height",
|
||||
orientation: "horizontal"
|
||||
},
|
||||
bottom: {
|
||||
edge: "bottom",
|
||||
opposite: "top",
|
||||
dimension: "height",
|
||||
orientation: "horizontal",
|
||||
reversed: true
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements `mct-split-pane` directive.
|
||||
*
|
||||
* This takes the following attributes:
|
||||
* * `position`: Two-way bound scope variable which will contain
|
||||
* the pixel position of the splitter, offset from the appropriate
|
||||
* edge.
|
||||
* * `anchor`: Plain string, one of "left", "right", "top",
|
||||
* or "bottom".
|
||||
*
|
||||
* When used, an `mct-split-pane` element should contain exactly
|
||||
* three child elements, where the middle is an `mct-splitter`
|
||||
* element. These should be included in either left-to-right
|
||||
* or top-to-bottom order (depending on anchoring.) If the contents
|
||||
* do not match this form, `mct-split-pane` will issue a warning
|
||||
* and its behavior will be undefined.
|
||||
*
|
||||
* This directive works by setting the width of the element
|
||||
* nearest the anchor edge, and then positioning the other elements
|
||||
* based on its observed width. As such, `min-width`, `max-width`,
|
||||
* etc. can be set on that element to control the splitter's
|
||||
* allowable positions.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function MCTSplitPane($parse, $log) {
|
||||
var anchors = {
|
||||
left: true,
|
||||
right: true,
|
||||
top: true,
|
||||
bottom: true
|
||||
};
|
||||
|
||||
function controller($scope, $element, $attrs) {
|
||||
var anchorKey = $attrs.anchor || DEFAULT_ANCHOR,
|
||||
anchor,
|
||||
positionParsed = $parse($attrs.position),
|
||||
position; // Start undefined, until explicitly set
|
||||
|
||||
// Get relevant size (height or width) of DOM element
|
||||
function getSize(domElement) {
|
||||
return (anchor.orientation === 'vertical' ?
|
||||
domElement.offsetWidth : domElement.offsetHeight);
|
||||
}
|
||||
|
||||
// Apply styles to child elements
|
||||
function updateChildren(children) {
|
||||
// Pick out correct elements to update, flowing from
|
||||
// selected anchor edge.
|
||||
var first = children.eq(anchor.reversed ? 2 : 0),
|
||||
splitter = children.eq(1),
|
||||
last = children.eq(anchor.reversed ? 0 : 2),
|
||||
splitterSize = getSize(splitter[0]),
|
||||
firstSize;
|
||||
|
||||
first.css(anchor.edge, "0px");
|
||||
first.css(anchor.dimension, (position - splitterSize) + 'px');
|
||||
|
||||
// Get actual size (to obey min-width etc.)
|
||||
firstSize = getSize(first[0]);
|
||||
first.css(anchor.dimension, firstSize + 'px');
|
||||
splitter.css(anchor.edge, (firstSize + splitterSize) + 'px');
|
||||
splitter.css(anchor.opposite, "auto");
|
||||
|
||||
last.css(anchor.edge, (firstSize + splitterSize * 3) + 'px');
|
||||
last.css(anchor.opposite, "0px");
|
||||
|
||||
position = firstSize + splitterSize;
|
||||
}
|
||||
|
||||
// Update positioning of contained elements
|
||||
function updateElementPositions() {
|
||||
var children = $element.children();
|
||||
|
||||
// Check to make sure contents are well-formed
|
||||
if (children.length !== 3 ||
|
||||
children[1].nodeName.toLowerCase() !== 'mct-splitter') {
|
||||
$log.warn(CHILDREN_WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
updateChildren(children);
|
||||
}
|
||||
|
||||
// Enforce minimum/maximum positions
|
||||
function enforceExtrema() {
|
||||
position = Math.max(position, 0);
|
||||
position = Math.min(position, getSize($element[0]));
|
||||
}
|
||||
|
||||
// Getter-setter for the pixel offset of the splitter,
|
||||
// relative to the current edge.
|
||||
function getSetPosition(value) {
|
||||
var min, max;
|
||||
if (typeof value === 'number') {
|
||||
position = value;
|
||||
enforceExtrema();
|
||||
updateElementPositions();
|
||||
|
||||
// Pass change up so this state can be shared
|
||||
if (positionParsed.assign) {
|
||||
positionParsed.assign($scope, position);
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
// Make sure anchor parameter is something we know
|
||||
if (!ANCHORS[anchorKey]) {
|
||||
$log.warn(ANCHOR_WARNING_MESSAGE);
|
||||
anchorKey = DEFAULT_ANCHOR;
|
||||
}
|
||||
anchor = ANCHORS[anchorKey];
|
||||
|
||||
$scope.$watch($attrs.position, getSetPosition);
|
||||
|
||||
$element.addClass("split-layout");
|
||||
$element.addClass(anchor.orientation);
|
||||
|
||||
// Initialize positions
|
||||
getSetPosition(getSize(
|
||||
$element.children().eq(anchor.reversed ? 2 : 0)[0]
|
||||
));
|
||||
|
||||
// Interface exposed by controller, for mct-splitter to user
|
||||
return {
|
||||
position: getSetPosition,
|
||||
anchor: function () {
|
||||
return anchor;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
// Restrict to attributes
|
||||
restrict: "E",
|
||||
// Expose its controller
|
||||
controller: ['$scope', '$element', '$attrs', controller]
|
||||
};
|
||||
}
|
||||
|
||||
return MCTSplitPane;
|
||||
|
||||
}
|
||||
);
|
90
platform/commonUI/general/src/directives/MCTSplitter.js
Normal file
90
platform/commonUI/general/src/directives/MCTSplitter.js
Normal file
@ -0,0 +1,90 @@
|
||||
/*****************************************************************************
|
||||
* 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';
|
||||
|
||||
// Pixel width to allocate for the splitter itself
|
||||
var SPLITTER_TEMPLATE = "<div class='abs'" +
|
||||
"mct-drag-down=\"splitter.startMove()\" " +
|
||||
"mct-drag=\"splitter.move(delta)\"></div>",
|
||||
OFFSETS_BY_EDGE = {
|
||||
left: "offsetLeft",
|
||||
right: "offsetRight",
|
||||
top: "offsetTop",
|
||||
bottom: "offsetBottom"
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements `mct-splitter` directive.
|
||||
* @constructor
|
||||
*/
|
||||
function MCTSplitter() {
|
||||
function link(scope, element, attrs, mctSplitPane) {
|
||||
var initialPosition;
|
||||
|
||||
element.addClass("splitter");
|
||||
|
||||
// Now that we have the above class, the splitter width
|
||||
// will have changed, so trigger a positioning update.
|
||||
mctSplitPane.position(mctSplitPane.position());
|
||||
|
||||
scope.splitter = {
|
||||
// Begin moving this splitter
|
||||
startMove: function () {
|
||||
var splitter = element[0];
|
||||
initialPosition = mctSplitPane.position();
|
||||
},
|
||||
// Handle user changes to splitter position
|
||||
move: function (delta) {
|
||||
var anchor = mctSplitPane.anchor(),
|
||||
index = anchor.orientation === "vertical" ? 0 : 1,
|
||||
pixelDelta = delta[index] *
|
||||
(anchor.reversed ? -1 : 1);
|
||||
|
||||
// Update the position of this splitter
|
||||
mctSplitPane.position(initialPosition + pixelDelta);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
// Restrict to attributes
|
||||
restrict: "E",
|
||||
// Utilize the mct-split-pane controller
|
||||
require: "^mctSplitPane",
|
||||
// Expose its controller
|
||||
link: link,
|
||||
// Use the template defined above
|
||||
template: SPLITTER_TEMPLATE,
|
||||
// Create a new scope to put the splitter into
|
||||
scope: true
|
||||
};
|
||||
}
|
||||
|
||||
return MCTSplitter;
|
||||
|
||||
}
|
||||
);
|
@ -39,34 +39,52 @@ define(
|
||||
// is returned. The view is defaulted to
|
||||
// the current location's (current object's)
|
||||
// view set.
|
||||
function urlFor(mode, domainObject) {
|
||||
function urlForLocation(mode, domainObject) {
|
||||
var context = domainObject &&
|
||||
domainObject.getCapability('context'),
|
||||
objectPath = context ? context.getPath() : [],
|
||||
ids = objectPath.map(function (domainObject) {
|
||||
return domainObject.getId();
|
||||
}),
|
||||
viewPath = "?view=" + $location.search().view,
|
||||
// Parses the path together. Starts with the
|
||||
// default index.html file, then the mode passed
|
||||
// into the service, followed by ids in the url
|
||||
// joined by '/', and lastly the view path from
|
||||
// the current location
|
||||
path = "index.html#/" + mode + "/" +
|
||||
ids.slice(1).join("/") + viewPath;
|
||||
|
||||
path = mode + "/" + ids.slice(1).join("/");
|
||||
return path;
|
||||
}
|
||||
|
||||
// Uses the Url for the current location
|
||||
// from the urlForLocation function and
|
||||
// includes the view and the index path
|
||||
function urlForNewTab(mode, domainObject) {
|
||||
var viewPath = "?view=" + $location.search().view,
|
||||
newTabPath =
|
||||
"index.html#" + urlForLocation(mode, domainObject) + viewPath;
|
||||
return newTabPath;
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Returns the Url path for a specific domain object
|
||||
* without the index.html path and the view path
|
||||
* @param {value} value of the browse or edit mode
|
||||
* for the path
|
||||
* @param {DomainObject} value of the domain object
|
||||
* to get the path of
|
||||
*/
|
||||
urlFor: urlFor
|
||||
urlForNewTab: urlForNewTab,
|
||||
/**
|
||||
* Returns the Url path for a specific domain object
|
||||
* including the index.html path and the view path
|
||||
* allowing a new tab to hold the correct characteristics
|
||||
* @param {value} value of the browse or edit mode
|
||||
* for the path
|
||||
* @param {DomainObject} value of the domain object
|
||||
* to get the path of
|
||||
*/
|
||||
urlForLocation: urlForLocation
|
||||
};
|
||||
}
|
||||
|
@ -81,10 +81,11 @@ define(
|
||||
});
|
||||
|
||||
it("invokes mctDragDown when dragging begins", function () {
|
||||
mockElement.on.mostRecentCall.args[1](testEvent(42, 60));
|
||||
var event = testEvent(42, 60);
|
||||
mockElement.on.mostRecentCall.args[1](event);
|
||||
expect(mockScope.$eval).toHaveBeenCalledWith(
|
||||
testAttrs.mctDragDown,
|
||||
{ delta: [0, 0] }
|
||||
{ delta: [0, 0], $event: event }
|
||||
);
|
||||
});
|
||||
|
||||
@ -101,23 +102,27 @@ define(
|
||||
});
|
||||
|
||||
it("invokes mctDrag expression during drag", function () {
|
||||
var event;
|
||||
|
||||
mockElement.on.mostRecentCall.args[1](testEvent(42, 60));
|
||||
|
||||
// Find and invoke the mousemove listener
|
||||
mockBody.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === 'mousemove') {
|
||||
call.args[1](testEvent(52, 200));
|
||||
call.args[1](event = testEvent(52, 200));
|
||||
}
|
||||
});
|
||||
|
||||
// Should have passed that delta to mct-drag expression
|
||||
expect(mockScope.$eval).toHaveBeenCalledWith(
|
||||
testAttrs.mctDrag,
|
||||
{ delta: [10, 140] }
|
||||
{ delta: [10, 140], $event: event }
|
||||
);
|
||||
});
|
||||
|
||||
it("invokes mctDragUp expression after drag", function () {
|
||||
var event;
|
||||
|
||||
mockElement.on.mostRecentCall.args[1](testEvent(42, 60));
|
||||
|
||||
// Find and invoke the mousemove listener
|
||||
@ -129,7 +134,7 @@ define(
|
||||
// Find and invoke the mousemove listener
|
||||
mockBody.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === 'mouseup') {
|
||||
call.args[1](testEvent(40, 71));
|
||||
call.args[1](event = testEvent(40, 71));
|
||||
}
|
||||
});
|
||||
|
||||
@ -138,7 +143,7 @@ define(
|
||||
// initial position
|
||||
expect(mockScope.$eval).toHaveBeenCalledWith(
|
||||
testAttrs.mctDragUp,
|
||||
{ delta: [-2, 11] }
|
||||
{ delta: [-2, 11], $event: event }
|
||||
);
|
||||
|
||||
// Should also have unregistered listeners
|
||||
@ -147,4 +152,4 @@ define(
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -31,7 +31,11 @@ define(
|
||||
|
||||
describe("The url service", function () {
|
||||
var urlService,
|
||||
mockLocation;
|
||||
mockLocation,
|
||||
mockDomainObject,
|
||||
mockContext,
|
||||
mockMode,
|
||||
testViews;
|
||||
|
||||
beforeEach(function () {
|
||||
// Creates a mockLocation, used to
|
||||
@ -41,24 +45,20 @@ define(
|
||||
[ "path", "search" ]
|
||||
);
|
||||
|
||||
urlService = new UrlService(mockLocation);
|
||||
});
|
||||
|
||||
it("get url for a domainObject and mode", function () {
|
||||
// The mockDomainObject is initialized as a
|
||||
// The mockDomainObject is initialized as a
|
||||
// spy object to ultimately be passed into the
|
||||
// urlService urlFor function
|
||||
var mockDomainObject = jasmine.createSpyObj(
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[ "getId", "getCapability", "getModel", "useCapability" ]
|
||||
),
|
||||
mockContext = jasmine.createSpyObj('context', ['getPath']),
|
||||
testViews = [
|
||||
{ key: 'abc' },
|
||||
{ key: 'def', someKey: 'some value' },
|
||||
{ key: 'xyz' }
|
||||
],
|
||||
mockMode = "browse";
|
||||
);
|
||||
mockContext = jasmine.createSpyObj('context', ['getPath']);
|
||||
testViews = [
|
||||
{ key: 'abc' },
|
||||
{ key: 'def', someKey: 'some value' },
|
||||
{ key: 'xyz' }
|
||||
];
|
||||
mockMode = "browse";
|
||||
|
||||
// The mockContext is set a path
|
||||
// for the mockDomainObject
|
||||
@ -81,8 +81,17 @@ define(
|
||||
// Uses the mockLocation to get the current
|
||||
// "mock" website's view
|
||||
mockLocation.search.andReturn({ view: 'def' });
|
||||
urlService.urlFor(mockMode, mockDomainObject);
|
||||
|
||||
urlService = new UrlService(mockLocation);
|
||||
});
|
||||
|
||||
it("get url for a location using domainObject and mode", function () {
|
||||
urlService.urlForLocation(mockMode, mockDomainObject);
|
||||
});
|
||||
|
||||
it("get url for a new tab using domainObject and mode", function () {
|
||||
urlService.urlForNewTab(mockMode, mockDomainObject);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -13,5 +13,6 @@
|
||||
"directives/MCTDrag",
|
||||
"directives/MCTResize",
|
||||
"directives/MCTScroll",
|
||||
"services/UrlService",
|
||||
"StyleSheetLoader"
|
||||
]
|
@ -183,7 +183,7 @@
|
||||
{
|
||||
"key": "mutation",
|
||||
"implementation": "capabilities/MutationCapability.js",
|
||||
"depends": [ "now" ]
|
||||
"depends": [ "topic", "now" ]
|
||||
},
|
||||
{
|
||||
"key": "delegation",
|
||||
@ -200,6 +200,10 @@
|
||||
"key": "throttle",
|
||||
"implementation": "services/Throttle.js",
|
||||
"depends": [ "$timeout" ]
|
||||
},
|
||||
{
|
||||
"key": "topic",
|
||||
"implementation": "services/Topic.js"
|
||||
}
|
||||
],
|
||||
"roots": [
|
||||
|
@ -29,6 +29,8 @@ define(
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var TOPIC_PREFIX = "mutation:";
|
||||
|
||||
// Utility function to overwrite a destination object
|
||||
// with the contents of a source object.
|
||||
function copyValues(destination, source) {
|
||||
@ -71,7 +73,8 @@ define(
|
||||
* which will expose this capability
|
||||
* @constructor
|
||||
*/
|
||||
function MutationCapability(now, domainObject) {
|
||||
function MutationCapability(topic, now, domainObject) {
|
||||
var t = topic(TOPIC_PREFIX + domainObject.getId());
|
||||
|
||||
function mutate(mutator, timestamp) {
|
||||
// Get the object's model and clone it, so the
|
||||
@ -96,6 +99,7 @@ define(
|
||||
copyValues(model, result);
|
||||
}
|
||||
model.modified = useTimestamp ? timestamp : now();
|
||||
t.notify(model);
|
||||
}
|
||||
|
||||
// Report the result of the mutation
|
||||
@ -107,6 +111,10 @@ define(
|
||||
return fastPromise(mutator(clone)).then(handleMutation);
|
||||
}
|
||||
|
||||
function listen(listener) {
|
||||
return t.listen(listener);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Alias of `mutate`, used to support useCapability.
|
||||
@ -139,10 +147,19 @@ define(
|
||||
* @returns {Promise.<boolean>} a promise for the result
|
||||
* of the mutation; true if changes were made.
|
||||
*/
|
||||
mutate: mutate
|
||||
mutate: mutate,
|
||||
/**
|
||||
* Listen for mutations of this domain object's model.
|
||||
* The provided listener will be invoked with the domain
|
||||
* object's new model after any changes. To stop listening,
|
||||
* invoke the function returned by this method.
|
||||
* @param {Function} listener function to call on mutation
|
||||
* @returns {Function} a function to stop listening
|
||||
*/
|
||||
listen: listen
|
||||
};
|
||||
}
|
||||
|
||||
return MutationCapability;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -1,3 +1,24 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
|
87
platform/core/src/services/Topic.js
Normal file
87
platform/core/src/services/Topic.js
Normal file
@ -0,0 +1,87 @@
|
||||
/*****************************************************************************
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* The `topic` service provides a way to create both named,
|
||||
* shared listeners and anonymous, private listeners.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ```
|
||||
* var t = topic('foo'); // Use/create a named topic
|
||||
* t.listen(function () { ... });
|
||||
* t.notify({ some: "message" });
|
||||
* ```
|
||||
*
|
||||
* Named topics are shared; multiple calls to `topic`
|
||||
* with the same argument will return a single object instance.
|
||||
* Anonymous topics (where `topic` has been called with no
|
||||
* arguments) are private; each call returns a new instance.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
function Topic() {
|
||||
var topics = {};
|
||||
|
||||
function createTopic() {
|
||||
var listeners = [];
|
||||
|
||||
return {
|
||||
listen: function (listener) {
|
||||
listeners.push(listener);
|
||||
return function unlisten() {
|
||||
listeners = listeners.filter(function (l) {
|
||||
return l !== listener;
|
||||
});
|
||||
};
|
||||
},
|
||||
notify: function (message) {
|
||||
listeners.forEach(function (listener) {
|
||||
listener(message);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Use and (if necessary) create a new topic.
|
||||
* @param {string} [key] name of the topic to use
|
||||
*/
|
||||
return function (key) {
|
||||
if (arguments.length < 1) {
|
||||
return createTopic();
|
||||
} else {
|
||||
topics[key] = topics[key] || createTopic();
|
||||
return topics[key];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return Topic;
|
||||
}
|
||||
);
|
@ -25,21 +25,33 @@
|
||||
* MutationCapabilitySpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
["../../src/capabilities/MutationCapability"],
|
||||
function (MutationCapability) {
|
||||
[
|
||||
"../../src/capabilities/MutationCapability",
|
||||
"../../src/services/Topic"
|
||||
],
|
||||
function (MutationCapability, Topic) {
|
||||
"use strict";
|
||||
|
||||
describe("The mutation capability", function () {
|
||||
var testModel,
|
||||
topic,
|
||||
mockNow,
|
||||
domainObject = { getModel: function () { return testModel; } },
|
||||
domainObject = {
|
||||
getId: function () { return "test-id"; },
|
||||
getModel: function () { return testModel; }
|
||||
},
|
||||
mutation;
|
||||
|
||||
beforeEach(function () {
|
||||
testModel = { number: 6 };
|
||||
topic = new Topic();
|
||||
mockNow = jasmine.createSpy('now');
|
||||
mockNow.andReturn(12321);
|
||||
mutation = new MutationCapability(mockNow, domainObject);
|
||||
mutation = new MutationCapability(
|
||||
topic,
|
||||
mockNow,
|
||||
domainObject
|
||||
);
|
||||
});
|
||||
|
||||
it("allows mutation of a model", function () {
|
||||
@ -83,6 +95,42 @@ define(
|
||||
// Should have gotten a timestamp from 'now'
|
||||
expect(testModel.modified).toEqual(42);
|
||||
});
|
||||
|
||||
it("notifies listeners of mutation", function () {
|
||||
var mockCallback = jasmine.createSpy('callback');
|
||||
mutation.listen(mockCallback);
|
||||
mutation.invoke(function (m) {
|
||||
m.number = 8;
|
||||
});
|
||||
expect(mockCallback).toHaveBeenCalled();
|
||||
expect(mockCallback.mostRecentCall.args[0].number)
|
||||
.toEqual(8);
|
||||
});
|
||||
|
||||
it("allows listeners to stop listening", function () {
|
||||
var mockCallback = jasmine.createSpy('callback');
|
||||
mutation.listen(mockCallback)(); // Unlisten immediately
|
||||
mutation.invoke(function (m) {
|
||||
m.number = 8;
|
||||
});
|
||||
expect(mockCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shares listeners across instances", function () {
|
||||
var mockCallback = jasmine.createSpy('callback'),
|
||||
otherMutation = new MutationCapability(
|
||||
topic,
|
||||
mockNow,
|
||||
domainObject
|
||||
);
|
||||
mutation.listen(mockCallback);
|
||||
otherMutation.invoke(function (m) {
|
||||
m.number = 8;
|
||||
});
|
||||
expect(mockCallback).toHaveBeenCalled();
|
||||
expect(mockCallback.mostRecentCall.args[0].number)
|
||||
.toEqual(8);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -1,3 +1,24 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
define(
|
||||
|
70
platform/core/test/services/TopicSpec.js
Normal file
70
platform/core/test/services/TopicSpec.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*/
|
||||
|
||||
define(
|
||||
["../../src/services/Topic"],
|
||||
function (Topic) {
|
||||
"use strict";
|
||||
|
||||
describe("The 'topic' service", function () {
|
||||
var topic,
|
||||
testMessage,
|
||||
mockCallback;
|
||||
|
||||
beforeEach(function () {
|
||||
testMessage = { someKey: "some value"};
|
||||
mockCallback = jasmine.createSpy('callback');
|
||||
topic = new Topic();
|
||||
});
|
||||
|
||||
it("notifies listeners on a topic", function () {
|
||||
topic("abc").listen(mockCallback);
|
||||
topic("abc").notify(testMessage);
|
||||
expect(mockCallback).toHaveBeenCalledWith(testMessage);
|
||||
});
|
||||
|
||||
it("does not notify listeners across topics", function () {
|
||||
topic("abc").listen(mockCallback);
|
||||
topic("xyz").notify(testMessage);
|
||||
expect(mockCallback).not.toHaveBeenCalledWith(testMessage);
|
||||
});
|
||||
|
||||
it("does not notify listeners after unlistening", function () {
|
||||
topic("abc").listen(mockCallback)(); // Unlisten immediately
|
||||
topic("abc").notify(testMessage);
|
||||
expect(mockCallback).not.toHaveBeenCalledWith(testMessage);
|
||||
});
|
||||
|
||||
it("provides anonymous private topics", function () {
|
||||
var t1 = topic(), t2 = topic();
|
||||
|
||||
t1.listen(mockCallback);
|
||||
t2.notify(testMessage);
|
||||
expect(mockCallback).not.toHaveBeenCalledWith(testMessage);
|
||||
t1.notify(testMessage);
|
||||
expect(mockCallback).toHaveBeenCalledWith(testMessage);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -25,6 +25,7 @@
|
||||
|
||||
"services/Now",
|
||||
"services/Throttle",
|
||||
"services/Topic",
|
||||
|
||||
"types/MergeModels",
|
||||
"types/TypeCapability",
|
||||
@ -35,4 +36,4 @@
|
||||
|
||||
"views/ViewCapability",
|
||||
"views/ViewProvider"
|
||||
]
|
||||
]
|
||||
|
37
platform/features/events/bundle.json
Normal file
37
platform/features/events/bundle.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "Event Messages",
|
||||
"description": "List of time-ordered event messages",
|
||||
"extensions": {
|
||||
"views": [
|
||||
{
|
||||
"key": "messages",
|
||||
"name": "Messages",
|
||||
"glyph": "5",
|
||||
"description": "Scrolling list of messages.",
|
||||
"templateUrl": "templates/messages.html",
|
||||
"needs": [ "telemetry" ],
|
||||
"delegation": true
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "EventListController",
|
||||
"implementation": "EventListController.js",
|
||||
"depends": [ "$scope", "telemetryFormatter" ]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctDataTable",
|
||||
"implementation": "directives/MCTDataTable.js",
|
||||
"depends": [ "$window" ]
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"category": "view",
|
||||
"implementation": "policies/MessagesViewPolicy.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
37
platform/features/events/res/templates/mct-data-table.html
Normal file
37
platform/features/events/res/templates/mct-data-table.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<table class="tabular">
|
||||
<thead>
|
||||
<tr>
|
||||
<th ng-repeat="header in headers">
|
||||
{{header}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="row in rows">
|
||||
<td ng-repeat="cell in row">
|
||||
{{cell}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
29
platform/features/events/res/templates/messages.html
Normal file
29
platform/features/events/res/templates/messages.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<div class="w1" ng-controller="TelemetryController as telemetry">
|
||||
<div class="w2"
|
||||
ng-controller="EventListController">
|
||||
<mct-data-table headers="headers" rows="rows" ascending-scroll="true"></mct-data-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
67
platform/features/events/src/DomainColumn.js
Normal file
67
platform/features/events/src/DomainColumn.js
Normal file
@ -0,0 +1,67 @@
|
||||
/*****************************************************************************
|
||||
* 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,moment*/
|
||||
|
||||
/**
|
||||
* Module defining DomainColumn. Created by vwoeltje on 11/18/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A column which will report telemetry domain values
|
||||
* (typically, timestamps.) Used by the ScrollingListController.
|
||||
*
|
||||
* @constructor
|
||||
* @param domainMetadata an object with the machine- and human-
|
||||
* readable names for this domain (in `key` and `name`
|
||||
* fields, respectively.)
|
||||
* @param {TelemetryFormatter} telemetryFormatter the telemetry
|
||||
* formatting service, for making values human-readable.
|
||||
*/
|
||||
function DomainColumn(domainMetadata, telemetryFormatter) {
|
||||
return {
|
||||
/**
|
||||
* Get the title to display in this column's header.
|
||||
* @returns {string} the title to display
|
||||
*/
|
||||
getTitle: function () {
|
||||
return domainMetadata.name;
|
||||
},
|
||||
/**
|
||||
* Get the text to display inside a row under this
|
||||
* column.
|
||||
* @returns {string} the text to display
|
||||
*/
|
||||
getValue: function (domainObject, data, index) {
|
||||
return telemetryFormatter.formatDomainValue(
|
||||
data.getDomainValue(index, domainMetadata.key)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return DomainColumn;
|
||||
}
|
||||
);
|
133
platform/features/events/src/EventListController.js
Normal file
133
platform/features/events/src/EventListController.js
Normal file
@ -0,0 +1,133 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining EventListController.
|
||||
* Created by chacskaylo on 06/18/2015.
|
||||
* Modified by shale on 06/23/2015.
|
||||
*/
|
||||
define(
|
||||
["./DomainColumn", "./RangeColumn", "./EventListPopulator"],
|
||||
function (DomainColumn, RangeColumn, EventListPopulator) {
|
||||
"use strict";
|
||||
|
||||
var ROW_COUNT = 100;
|
||||
|
||||
/**
|
||||
* The EventListController is responsible for populating
|
||||
* the contents of the event list view.
|
||||
* @constructor
|
||||
*/
|
||||
function EventListController($scope, formatter) {
|
||||
var populator;
|
||||
|
||||
// Get a set of populated, ready-to-display rows for the
|
||||
// latest data values.
|
||||
function getRows(telemetry) {
|
||||
var datas = telemetry.getResponse(),
|
||||
objects = telemetry.getTelemetryObjects();
|
||||
|
||||
return populator.getRows(datas, objects, ROW_COUNT);
|
||||
}
|
||||
|
||||
// Update the contents
|
||||
function updateRows() {
|
||||
var telemetry = $scope.telemetry;
|
||||
$scope.rows = telemetry ? getRows(telemetry) : [];
|
||||
}
|
||||
|
||||
// Set up columns based on telemetry metadata. This will
|
||||
// include one column for each domain and range type, as
|
||||
// well as a column for the domain object name.
|
||||
function setupColumns(telemetry) {
|
||||
var domainKeys = {},
|
||||
rangeKeys = {},
|
||||
columns = [],
|
||||
metadata;
|
||||
|
||||
// Add a domain to the set of columns, if a domain
|
||||
// with the same key has not yet been inclued.
|
||||
function addDomain(domain) {
|
||||
var key = domain.key;
|
||||
if (key && !domainKeys[key]) {
|
||||
domainKeys[key] = true;
|
||||
columns.push(new DomainColumn(domain, formatter));
|
||||
}
|
||||
}
|
||||
|
||||
// Add a range col to the set of columns, if a range
|
||||
// with the same key has not yet been included.
|
||||
function addRange(range) {
|
||||
var key = range.key;
|
||||
if (key && !rangeKeys[key]) {
|
||||
rangeKeys[key] = true;
|
||||
columns.push(new RangeColumn(range, formatter));
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot proceed if the telemetry controller
|
||||
// is not available; clear all rows/columns.
|
||||
if (!telemetry) {
|
||||
columns = [];
|
||||
$scope.rows = [];
|
||||
$scope.headers = [];
|
||||
return;
|
||||
}
|
||||
|
||||
// Add domain, range, event msg columns
|
||||
metadata = telemetry.getMetadata();
|
||||
(metadata || []).forEach(function (metadata) {
|
||||
(metadata.domains || []).forEach(addDomain);
|
||||
});
|
||||
(metadata || []).forEach(function (metadata) {
|
||||
(metadata.ranges || []).forEach(addRange);
|
||||
});
|
||||
|
||||
// Add default domain and range columns if none
|
||||
// were described in metadata.
|
||||
if (Object.keys(domainKeys).length < 1) {
|
||||
columns.push(new DomainColumn({name: "Time"}, formatter));
|
||||
}
|
||||
if (Object.keys(rangeKeys).length < 1) {
|
||||
columns.push(new RangeColumn({name: "Message"}, formatter));
|
||||
}
|
||||
|
||||
// We have all columns now; use them to initializer
|
||||
// the populator, which will use them to generate
|
||||
// actual rows and headers.
|
||||
populator = new EventListPopulator(columns);
|
||||
|
||||
// Initialize headers
|
||||
$scope.headers = populator.getHeaders();
|
||||
|
||||
// Fill in the contents of the rows.
|
||||
updateRows();
|
||||
}
|
||||
|
||||
$scope.$on("telemetryUpdate", updateRows);
|
||||
$scope.$watch("telemetry", setupColumns);
|
||||
}
|
||||
|
||||
return EventListController;
|
||||
}
|
||||
);
|
161
platform/features/events/src/EventListPopulator.js
Normal file
161
platform/features/events/src/EventListPopulator.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*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The EventListPopulator is responsible for filling in the
|
||||
* values which should appear within columns of a event list
|
||||
* view, based on received telemetry data.
|
||||
* @constructor
|
||||
* @param {Column[]} columns the columns to be populated
|
||||
*/
|
||||
function EventListPopulator(columns) {
|
||||
/**
|
||||
* Look up the most recent values from a set of data objects.
|
||||
* Returns an array of objects in the order in which data
|
||||
* should be displayed; each element is an object with
|
||||
* two properties:
|
||||
*
|
||||
* * objectIndex: The index of the domain object associated
|
||||
* with the data point to be displayed in that
|
||||
* row.
|
||||
* * pointIndex: The index of the data point itself, within
|
||||
* its data set.
|
||||
*
|
||||
* @param {Array<Telemetry>} datas an array of the most recent
|
||||
* data objects; expected to be in the same order
|
||||
* as the domain objects provided at constructor
|
||||
* @param {number} count the number of rows to provide
|
||||
*/
|
||||
function getLatestDataValues(datas, count) {
|
||||
var latest = [],
|
||||
candidate,
|
||||
candidateTime,
|
||||
used = datas.map(function () { return 0; });
|
||||
|
||||
// This algorithm is O(nk) for n rows and k telemetry elements;
|
||||
// one O(k) linear search for a max is made for each of n rows.
|
||||
// This could be done in O(n lg k + k lg k), using a priority
|
||||
// queue (where priority is max-finding) containing k initial
|
||||
// values. For n rows, pop the max from the queue and replenish
|
||||
// the queue with a value from the data at the same
|
||||
// objectIndex, if available.
|
||||
// But k is small, so this might not give an observable
|
||||
// improvement in performance.
|
||||
|
||||
// Find the most recent unused data point (this will be used
|
||||
// in a loop to find and the N most recent data points)
|
||||
function findCandidate(data, i) {
|
||||
var nextTime,
|
||||
pointCount = data.getPointCount(),
|
||||
pointIndex = pointCount - used[i] - 1;
|
||||
if (data && pointIndex >= 0) {
|
||||
nextTime = data.getDomainValue(pointIndex);
|
||||
if (nextTime > candidateTime) {
|
||||
candidateTime = nextTime;
|
||||
candidate = {
|
||||
objectIndex: i,
|
||||
pointIndex: pointIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble a list of the most recent data points
|
||||
while (latest.length < count) {
|
||||
// Reset variables pre-search
|
||||
candidateTime = Number.NEGATIVE_INFINITY;
|
||||
candidate = undefined;
|
||||
|
||||
// Linear search for most recent
|
||||
datas.forEach(findCandidate);
|
||||
|
||||
if (candidate) {
|
||||
// Record this data point - it is the most recent
|
||||
latest.push(candidate);
|
||||
|
||||
// Track the data points used so we can look farther back
|
||||
// in the data set on the next iteration
|
||||
used[candidate.objectIndex] = used[candidate.objectIndex] + 1;
|
||||
} else {
|
||||
// Ran out of candidates; not enough data points
|
||||
// available to fill all rows.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return latest;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the text which should appear in headers for the
|
||||
* provided columns.
|
||||
* @returns {string[]} column headers
|
||||
*/
|
||||
getHeaders: function () {
|
||||
return columns.map(function (column) {
|
||||
return column.getTitle();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Get the contents of rows for the event list view.
|
||||
* @param {TelemetrySeries[]} datas the data sets
|
||||
* @param {DomainObject[]} objects the domain objects which
|
||||
* provided the data sets; these should match
|
||||
* index-to-index with the `datas` argument
|
||||
* @param {number} count the number of rows to populate
|
||||
* @returns {string[][]} an array of rows, each of which
|
||||
* is an array of values which should appear
|
||||
* in that row
|
||||
*/
|
||||
getRows: function (datas, objects, count) {
|
||||
var values = getLatestDataValues(datas, count);
|
||||
|
||||
// Each value will become a row, which will contain
|
||||
// some value in each column (rendering by the
|
||||
// column object itself)
|
||||
// Additionally, we want to display the rows in reverse
|
||||
// order. (i.e. from the top to the bottom of the page)
|
||||
return values.map(function (value) {
|
||||
return columns.map(function (column) {
|
||||
return column.getValue(
|
||||
objects[value.objectIndex],
|
||||
datas[value.objectIndex],
|
||||
value.pointIndex
|
||||
);
|
||||
});
|
||||
}).reverse();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return EventListPopulator;
|
||||
|
||||
}
|
||||
);
|
67
platform/features/events/src/RangeColumn.js
Normal file
67
platform/features/events/src/RangeColumn.js
Normal file
@ -0,0 +1,67 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining DomainColumn. Created by vwoeltje on 11/18/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A column which will report telemetry range values
|
||||
* (typically, measurements.) Used by the ScrollingListController.
|
||||
*
|
||||
* @constructor
|
||||
* @param rangeMetadata an object with the machine- and human-
|
||||
* readable names for this range (in `key` and `name`
|
||||
* fields, respectively.)
|
||||
* @param {TelemetryFormatter} telemetryFormatter the telemetry
|
||||
* formatting service, for making values human-readable.
|
||||
*/
|
||||
function RangeColumn(rangeMetadata, telemetryFormatter) {
|
||||
return {
|
||||
/**
|
||||
* Get the title to display in this column's header.
|
||||
* @returns {string} the title to display
|
||||
*/
|
||||
getTitle: function () {
|
||||
return rangeMetadata.name;
|
||||
},
|
||||
/**
|
||||
* Get the text to display inside a row under this
|
||||
* column.
|
||||
* @returns {string} the text to display
|
||||
*/
|
||||
getValue: function (domainObject, data, index) {
|
||||
return telemetryFormatter.formatRangeValue(
|
||||
data.getRangeValue(index, rangeMetadata.key)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return RangeColumn;
|
||||
}
|
||||
);
|
74
platform/features/events/src/directives/MCTDataTable.js
Normal file
74
platform/features/events/src/directives/MCTDataTable.js
Normal file
@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining MCTDataTable. Created by shale on 06/22/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
function MCTDataTable($window) {
|
||||
return {
|
||||
restrict: "E",
|
||||
templateUrl: "platform/features/events/res/templates/mct-data-table.html",
|
||||
scope: {
|
||||
headers: "=",
|
||||
rows: "=",
|
||||
ascendingScroll: "="
|
||||
},
|
||||
link: function ($scope, $element) {
|
||||
var currentHeight,
|
||||
previousHeight,
|
||||
scrollParent;
|
||||
|
||||
// If the scroll is set to ascending, we want to
|
||||
// check when elements are added to the table, and move the scroll
|
||||
// bar accordingly.
|
||||
// (When viewing at the bottom of the page, the scroll bar will
|
||||
// stay at the bottom despite additions to the table)
|
||||
if ($scope.ascendingScroll) {
|
||||
$scope.$watch("rows", function () {
|
||||
// Wait until the page as been repainted (otherwise the
|
||||
// height will always be zero)
|
||||
$window.requestAnimationFrame(function () {
|
||||
previousHeight = currentHeight;
|
||||
// The height of the table body
|
||||
currentHeight = $element[0].firstElementChild.firstElementChild.nextElementSibling.clientHeight;
|
||||
|
||||
// One of the parents is a div that has vscroll
|
||||
scrollParent = $element[0].parentElement.parentElement.parentElement.parentElement.parentElement;
|
||||
|
||||
// Move the scrollbar down the amount that the height has changed
|
||||
scrollParent.scrollTop = scrollParent.scrollTop + (currentHeight - previousHeight);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTDataTable;
|
||||
}
|
||||
);
|
74
platform/features/events/src/policies/MessagesViewPolicy.js
Normal file
74
platform/features/events/src/policies/MessagesViewPolicy.js
Normal file
@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining MessagesViewPolicy. Created by shale on 06/24/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Policy controlling when the Messages view should be avaliable.
|
||||
* @constructor
|
||||
*/
|
||||
function MessagesViewPolicy() {
|
||||
|
||||
function hasStringTelemetry(domainObject) {
|
||||
var telemetry = domainObject &&
|
||||
domainObject.getCapability('telemetry'),
|
||||
metadata = telemetry ? telemetry.getMetadata() : {},
|
||||
ranges = metadata.ranges || [];
|
||||
|
||||
return ranges.some(function (range) {
|
||||
return range.format === 'string';
|
||||
});
|
||||
}
|
||||
return {
|
||||
/**
|
||||
* Check whether or not a given action is allowed by this
|
||||
* policy.
|
||||
* @param {Action} action the action
|
||||
* @param domainObject the domain object which will be viewed
|
||||
* @returns {boolean} true if not disallowed
|
||||
*/
|
||||
allow: function (view, domainObject) {
|
||||
// This policy only applies for the Messages view
|
||||
if (view.key === 'messages') {
|
||||
// The Messages view is allowed only if the domain
|
||||
// object has string telemetry
|
||||
if (!hasStringTelemetry(domainObject)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Like all policies, allow by default.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return MessagesViewPolicy;
|
||||
}
|
||||
);
|
84
platform/features/events/test/DomainColumnSpec.js
Normal file
84
platform/features/events/test/DomainColumnSpec.js
Normal file
@ -0,0 +1,84 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* EventSpec. Created by vwoeltje on 11/6/14. Modified by shale on 06/23/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/DomainColumn"],
|
||||
function (DomainColumn) {
|
||||
"use strict";
|
||||
|
||||
var TEST_DOMAIN_VALUE = "some formatted domain value";
|
||||
|
||||
describe("An event list domain column", function () {
|
||||
var mockDataSet,
|
||||
testMetadata,
|
||||
mockFormatter,
|
||||
column;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDataSet = jasmine.createSpyObj(
|
||||
"data",
|
||||
[ "getDomainValue" ]
|
||||
);
|
||||
mockFormatter = jasmine.createSpyObj(
|
||||
"formatter",
|
||||
[ "formatDomainValue", "formatRangeValue" ]
|
||||
);
|
||||
testMetadata = {
|
||||
key: "testKey",
|
||||
name: "Test Name"
|
||||
};
|
||||
mockFormatter.formatDomainValue.andReturn(TEST_DOMAIN_VALUE);
|
||||
|
||||
column = new DomainColumn(testMetadata, mockFormatter);
|
||||
});
|
||||
|
||||
it("reports a column header from domain metadata", function () {
|
||||
expect(column.getTitle()).toEqual("Test Name");
|
||||
});
|
||||
|
||||
it("looks up data from a data set", function () {
|
||||
column.getValue(undefined, mockDataSet, 42);
|
||||
expect(mockDataSet.getDomainValue)
|
||||
.toHaveBeenCalledWith(42, "testKey");
|
||||
});
|
||||
|
||||
it("formats domain values as time", function () {
|
||||
mockDataSet.getDomainValue.andReturn(402513731000);
|
||||
|
||||
// Should have just given the value the formatter gave
|
||||
expect(column.getValue(undefined, mockDataSet, 42))
|
||||
.toEqual(TEST_DOMAIN_VALUE);
|
||||
|
||||
// Make sure that service interactions were as expected
|
||||
expect(mockFormatter.formatDomainValue)
|
||||
.toHaveBeenCalledWith(402513731000);
|
||||
expect(mockFormatter.formatRangeValue)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
110
platform/features/events/test/EventListControllerSpec.js
Normal file
110
platform/features/events/test/EventListControllerSpec.js
Normal file
@ -0,0 +1,110 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* EventSpec. Created by shale on 06/24/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/EventListController"],
|
||||
function (EventListController) {
|
||||
"use strict";
|
||||
|
||||
describe("The event list controller", function () {
|
||||
var mockScope,
|
||||
mockTelemetry,
|
||||
testMetadata,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
[ "$on", "$watch" ]
|
||||
);
|
||||
mockTelemetry = jasmine.createSpyObj(
|
||||
"telemetryController",
|
||||
[ "getResponse", "getMetadata", "getTelemetryObjects" ]
|
||||
);
|
||||
testMetadata = [
|
||||
{
|
||||
domains: [
|
||||
{ key: "d0", name: "D0" },
|
||||
{ key: "d1", name: "D1" }
|
||||
],
|
||||
ranges: [
|
||||
{ key: "r0", name: "R0" },
|
||||
{ key: "r1", name: "R1" }
|
||||
]
|
||||
},
|
||||
{
|
||||
domains: [
|
||||
{ key: "d0", name: "D0" },
|
||||
{ key: "d2", name: "D2" }
|
||||
],
|
||||
ranges: [
|
||||
{ key: "r0", name: "R0" }
|
||||
]
|
||||
}
|
||||
];
|
||||
mockTelemetry.getMetadata.andReturn(testMetadata);
|
||||
mockTelemetry.getResponse.andReturn([]);
|
||||
mockTelemetry.getTelemetryObjects.andReturn([]);
|
||||
mockScope.telemetry = mockTelemetry;
|
||||
controller = new EventListController(mockScope);
|
||||
});
|
||||
|
||||
it("listens for telemetry data updates", function () {
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
"telemetryUpdate",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("watches for telemetry controller changes", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"telemetry",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("provides a column for each unique domain and range", function () {
|
||||
// Should have five columns based on metadata above,
|
||||
// (d0, d1, d2, r0, r1)
|
||||
mockScope.$watch.mostRecentCall.args[1](mockTelemetry);
|
||||
expect(mockScope.headers).toEqual(["D0", "D1", "D2", "R0", "R1"]);
|
||||
});
|
||||
|
||||
it("does not throw if telemetry controller is undefined", function () {
|
||||
// Just a general robustness check
|
||||
mockScope.telemetry = undefined;
|
||||
expect(mockScope.$watch.mostRecentCall.args[1])
|
||||
.not.toThrow();
|
||||
});
|
||||
|
||||
it("provides default columns if domain/range metadata is unavailable", function () {
|
||||
mockTelemetry.getMetadata.andReturn([]);
|
||||
mockScope.$watch.mostRecentCall.args[1](mockTelemetry);
|
||||
expect(mockScope.headers).toEqual(["Time", "Message"]);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
103
platform/features/events/test/EventListPopulatorSpec.js
Normal file
103
platform/features/events/test/EventListPopulatorSpec.js
Normal file
@ -0,0 +1,103 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* EventSpec. Created by shale on 06/24/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/EventListPopulator"],
|
||||
function (EventListPopulator) {
|
||||
"use strict";
|
||||
|
||||
describe("The event list populator", function () {
|
||||
var mockColumns,
|
||||
mockDatas,
|
||||
mockDomainObjects,
|
||||
populator;
|
||||
|
||||
function makeMockColumn(name, index) {
|
||||
var mockColumn = jasmine.createSpyObj(
|
||||
"column" + index,
|
||||
[ "getTitle", "getValue" ]
|
||||
);
|
||||
mockColumn.getTitle.andReturn(name);
|
||||
mockColumn.getValue.andCallFake(function (obj, data, i) {
|
||||
return data.getDomainValue(i);
|
||||
});
|
||||
return mockColumn;
|
||||
}
|
||||
|
||||
function makeMockData(bias, index) {
|
||||
var mockData = jasmine.createSpyObj(
|
||||
"data" + index,
|
||||
[ "getDomainValue", "getPointCount" ]
|
||||
);
|
||||
mockData.getPointCount.andReturn(1000);
|
||||
mockData.getDomainValue.andCallFake(function (i) {
|
||||
return i + bias;
|
||||
});
|
||||
return mockData;
|
||||
}
|
||||
|
||||
function makeMockDomainObject(name, index) {
|
||||
var mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject" + index,
|
||||
[ "getId", "getModel" ]
|
||||
);
|
||||
return mockDomainObject;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockColumns = ["A", "B", "C", "D"].map(makeMockColumn);
|
||||
mockDatas = [ 10, 0, 3 ].map(makeMockData);
|
||||
mockDomainObjects = ["A", "B", "C"].map(makeMockDomainObject);
|
||||
populator = new EventListPopulator(mockColumns);
|
||||
});
|
||||
|
||||
it("returns column headers", function () {
|
||||
expect(populator.getHeaders()).toEqual(["A", "B", "C", "D"]);
|
||||
});
|
||||
|
||||
it("provides rows on request, with all columns in each row", function () {
|
||||
var rows = populator.getRows(mockDatas, mockDomainObjects, 84);
|
||||
expect(rows.length).toEqual(84);
|
||||
rows.forEach(function (row) {
|
||||
expect(row.length).toEqual(4); // number of columns
|
||||
});
|
||||
});
|
||||
|
||||
it("returns rows in most-recent-last order", function () {
|
||||
var rows = populator.getRows(mockDatas, mockDomainObjects, 84),
|
||||
previous = Number.NEGATIVE_INFINITY;
|
||||
|
||||
// Should always be most-recent-last
|
||||
rows.forEach(function (row) {
|
||||
expect(row[0]).not.toBeLessThan(previous);
|
||||
previous = row[0];
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
81
platform/features/events/test/RangeColumnSpec.js
Normal file
81
platform/features/events/test/RangeColumnSpec.js
Normal file
@ -0,0 +1,81 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* EventSpec. Created by vwoeltje on 11/6/14. Modified by shale on 06/23/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/RangeColumn"],
|
||||
function (RangeColumn) {
|
||||
"use strict";
|
||||
|
||||
var TEST_RANGE_VALUE = "some formatted range value";
|
||||
|
||||
describe("An event list range column", function () {
|
||||
var mockDataSet,
|
||||
testMetadata,
|
||||
mockFormatter,
|
||||
column;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDataSet = jasmine.createSpyObj(
|
||||
"data",
|
||||
[ "getRangeValue" ]
|
||||
);
|
||||
mockFormatter = jasmine.createSpyObj(
|
||||
"formatter",
|
||||
[ "formatDomainValue", "formatRangeValue" ]
|
||||
);
|
||||
testMetadata = {
|
||||
key: "testKey",
|
||||
name: "Test Name"
|
||||
};
|
||||
mockFormatter.formatRangeValue.andReturn(TEST_RANGE_VALUE);
|
||||
|
||||
column = new RangeColumn(testMetadata, mockFormatter);
|
||||
});
|
||||
|
||||
it("reports a column header from range metadata", function () {
|
||||
expect(column.getTitle()).toEqual("Test Name");
|
||||
});
|
||||
|
||||
it("looks up data from a data set", function () {
|
||||
column.getValue(undefined, mockDataSet, 42);
|
||||
expect(mockDataSet.getRangeValue)
|
||||
.toHaveBeenCalledWith(42, "testKey");
|
||||
});
|
||||
|
||||
it("formats range values as time", function () {
|
||||
mockDataSet.getRangeValue.andReturn(123.45678);
|
||||
expect(column.getValue(undefined, mockDataSet, 42))
|
||||
.toEqual(TEST_RANGE_VALUE);
|
||||
|
||||
// Make sure that service interactions were as expected
|
||||
expect(mockFormatter.formatRangeValue)
|
||||
.toHaveBeenCalledWith(123.45678);
|
||||
expect(mockFormatter.formatDomainValue)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -0,0 +1,81 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* EventSpec. Created by shale on 06/24/2015.
|
||||
*/
|
||||
define(
|
||||
["../../src/policies/MessagesViewPolicy"],
|
||||
function (MessagesViewPolicy) {
|
||||
"use strict";
|
||||
|
||||
describe("The messages view policy", function () {
|
||||
var mockDomainObject,
|
||||
mockTelemetry,
|
||||
telemetryType,
|
||||
testType,
|
||||
testView,
|
||||
testMetadata,
|
||||
policy;
|
||||
|
||||
beforeEach(function () {
|
||||
|
||||
testView = { key: "string" };
|
||||
testMetadata = {};
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
['getModel', 'getCapability']
|
||||
);
|
||||
mockTelemetry = jasmine.createSpyObj(
|
||||
'telemetry',
|
||||
['getMetadata']
|
||||
);
|
||||
|
||||
mockDomainObject.getModel.andCallFake(function (c) {
|
||||
return {type: testType};
|
||||
});
|
||||
mockDomainObject.getCapability.andCallFake(function (c) {
|
||||
return c === 'telemetry' ? mockTelemetry : undefined;
|
||||
});
|
||||
mockTelemetry.getMetadata.andReturn(testMetadata);
|
||||
|
||||
policy = new MessagesViewPolicy();
|
||||
});
|
||||
|
||||
it("disallows the message view for objects without string telemetry", function () {
|
||||
testMetadata.ranges = [ { format: 'notString' } ];
|
||||
expect(policy.allow({ key: 'messages' }, mockDomainObject)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("allows the message view for objects with string telemetry", function () {
|
||||
testMetadata.ranges = [ { format: 'string' } ];
|
||||
expect(policy.allow({ key: 'messages' }, mockDomainObject)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("returns true when the current view is not the Messages view", function () {
|
||||
expect(policy.allow({ key: 'notMessages' }, mockDomainObject)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
7
platform/features/events/test/suite.json
Normal file
7
platform/features/events/test/suite.json
Normal file
@ -0,0 +1,7 @@
|
||||
[
|
||||
"DomainColumn",
|
||||
"EventListController",
|
||||
"EventListPopulator",
|
||||
"policies/MessagesViewPolicy",
|
||||
"RangeColumn"
|
||||
]
|
@ -194,6 +194,12 @@
|
||||
"templateUrl": "templates/elements/image.html"
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"category": "composition",
|
||||
"implementation": "LayoutCompositionPolicy.js"
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"key": "layout",
|
||||
@ -267,4 +273,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
<span
|
||||
class="l-elem l-value l-obj-val-format"
|
||||
data-value="{{ngModel.value}}"
|
||||
ng-class="ngModel.cssClass + ' ' + (ngModel.element.titled ? 'telem-only' : '')"
|
||||
ng-class="ngModel.cssClass"
|
||||
>
|
||||
{{ngModel.value}}
|
||||
</span>
|
||||
|
@ -20,14 +20,13 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="t-fixed-position l-fixed-position"
|
||||
ng-controller="FixedController as controller"
|
||||
mct-resize="controller.setBounds(bounds)">
|
||||
ng-controller="FixedController as controller">
|
||||
|
||||
<!-- Background grid -->
|
||||
<div class="l-grid-holder" ng-click="controller.clearSelection()">
|
||||
<div class="l-grid l-grid-x"
|
||||
<div class="l-grid l-grid-x"
|
||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
||||
<div class="l-grid l-grid-y"
|
||||
<div class="l-grid l-grid-y"
|
||||
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
||||
</div>
|
||||
|
||||
@ -60,4 +59,4 @@
|
||||
</div>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -27,8 +27,7 @@ define(
|
||||
"use strict";
|
||||
|
||||
var DEFAULT_DIMENSIONS = [ 2, 1 ],
|
||||
DEFAULT_GRID_SIZE = [64, 16],
|
||||
DEFAULT_GRID_EXTENT = [4, 4];
|
||||
DEFAULT_GRID_SIZE = [64, 16];
|
||||
|
||||
/**
|
||||
* The FixedController is responsible for supporting the
|
||||
@ -40,10 +39,8 @@ define(
|
||||
*/
|
||||
function FixedController($scope, $q, dialogService, telemetrySubscriber, telemetryFormatter) {
|
||||
var gridSize = DEFAULT_GRID_SIZE,
|
||||
gridExtent = DEFAULT_GRID_EXTENT,
|
||||
dragging,
|
||||
subscription,
|
||||
cellStyles = [],
|
||||
elementProxies = [],
|
||||
names = {}, // Cache names by ID
|
||||
values = {}, // Cache values by ID
|
||||
@ -52,29 +49,6 @@ define(
|
||||
moveHandle,
|
||||
selection;
|
||||
|
||||
// Refresh cell styles (e.g. because grid extent changed)
|
||||
function refreshCellStyles() {
|
||||
var x, y;
|
||||
|
||||
// Clear previous styles
|
||||
cellStyles = [];
|
||||
|
||||
// Update grid size from model
|
||||
gridSize = ($scope.model || {}).layoutGrid || gridSize;
|
||||
|
||||
for (x = 0; x < gridExtent[0]; x += 1) {
|
||||
for (y = 0; y < gridExtent[1]; y += 1) {
|
||||
// Position blocks; subtract out border size from w/h
|
||||
cellStyles.push({
|
||||
left: x * gridSize[0] + 'px',
|
||||
top: y * gridSize[1] + 'px',
|
||||
width: gridSize[0] - 1 + 'px',
|
||||
height: gridSize[1] - 1 + 'px'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert from element x/y/width/height to an
|
||||
// apropriate ng-style argument, to position elements.
|
||||
function convertPosition(elementProxy) {
|
||||
@ -143,6 +117,16 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
// Update element positions when grid size changes
|
||||
function updateElementPositions(layoutGrid) {
|
||||
// Update grid size from model
|
||||
gridSize = layoutGrid || DEFAULT_GRID_SIZE;
|
||||
|
||||
elementProxies.forEach(function (elementProxy) {
|
||||
elementProxy.style = convertPosition(elementProxy);
|
||||
});
|
||||
}
|
||||
|
||||
// Update telemetry values based on new data available
|
||||
function updateValues() {
|
||||
if (subscription) {
|
||||
@ -256,6 +240,11 @@ define(
|
||||
|
||||
// Position a panel after a drop event
|
||||
function handleDrop(e, id, position) {
|
||||
// Don't handle this event if it has already been handled
|
||||
if (e.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
// Store the position of this element.
|
||||
addElement({
|
||||
type: "fixed.telemetry",
|
||||
@ -284,6 +273,9 @@ define(
|
||||
// Position panes when the model field changes
|
||||
$scope.$watch("model.composition", updateComposition);
|
||||
|
||||
// Detect changes to grid size
|
||||
$scope.$watch("model.layoutGrid", updateElementPositions);
|
||||
|
||||
// Subscribe to telemetry when an object is available
|
||||
$scope.$watch("domainObject", subscribe);
|
||||
|
||||
@ -293,19 +285,7 @@ define(
|
||||
// Position panes where they are dropped
|
||||
$scope.$on("mctDrop", handleDrop);
|
||||
|
||||
// Initialize styles (position etc.) for cells
|
||||
refreshCellStyles();
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get styles for all background cells, as will populate the
|
||||
* ng-style tag.
|
||||
* @memberof FixedController#
|
||||
* @returns {Array} cell styles
|
||||
*/
|
||||
getCellStyles: function () {
|
||||
return cellStyles;
|
||||
},
|
||||
/**
|
||||
* Get the size of the grid, in pixels. The returned array
|
||||
* is in the form `[x, y]`.
|
||||
@ -314,19 +294,6 @@ define(
|
||||
getGridSize: function () {
|
||||
return gridSize;
|
||||
},
|
||||
/**
|
||||
* Set the size of the viewable fixed position area.
|
||||
* @memberof FixedController#
|
||||
* @param bounds the width/height, as reported by mct-resize
|
||||
*/
|
||||
setBounds: function (bounds) {
|
||||
var w = Math.ceil(bounds.width / gridSize[0]),
|
||||
h = Math.ceil(bounds.height / gridSize[1]);
|
||||
if (w !== gridExtent[0] || h !== gridExtent[1]) {
|
||||
gridExtent = [w, h];
|
||||
refreshCellStyles();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Get an array of elements in this panel; these are
|
||||
* decorated proxies for both selection and display.
|
||||
|
52
platform/features/layout/src/LayoutCompositionPolicy.js
Normal file
52
platform/features/layout/src/LayoutCompositionPolicy.js
Normal file
@ -0,0 +1,52 @@
|
||||
/*****************************************************************************
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* Defines composition policy for Display Layout objects.
|
||||
* They cannot contain folders.
|
||||
*/
|
||||
function LayoutCompositionPolicy() {
|
||||
return {
|
||||
/**
|
||||
* Is the type identified by the candidate allowed to
|
||||
* contain the type described by the context?
|
||||
*/
|
||||
allow: function (candidate, context) {
|
||||
var isFolderInLayout =
|
||||
candidate &&
|
||||
context &&
|
||||
candidate.instanceOf('layout') &&
|
||||
context.instanceOf('folder');
|
||||
return !isFolderInLayout;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return LayoutCompositionPolicy;
|
||||
}
|
||||
);
|
@ -109,6 +109,9 @@ define(
|
||||
|
||||
// Position a panel after a drop event
|
||||
function handleDrop(e, id, position) {
|
||||
if (e.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
// Ensure that configuration field is populated
|
||||
$scope.configuration = $scope.configuration || {};
|
||||
// Make sure there is a "panels" field in the
|
||||
@ -129,6 +132,10 @@ define(
|
||||
}
|
||||
// Populate template-facing position for this id
|
||||
populatePosition(id);
|
||||
// Layout may contain embedded views which will
|
||||
// listen for drops, so call preventDefault() so
|
||||
// that they can recognize that this event is handled.
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// Position panes when the model field changes
|
||||
@ -220,4 +227,4 @@ define(
|
||||
|
||||
return LayoutController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -34,6 +34,7 @@ define(
|
||||
mockFormatter,
|
||||
mockDomainObject,
|
||||
mockSubscription,
|
||||
mockEvent,
|
||||
testGrid,
|
||||
testModel,
|
||||
testValues,
|
||||
@ -98,6 +99,10 @@ define(
|
||||
'subscription',
|
||||
[ 'unsubscribe', 'getTelemetryObjects', 'getRangeValue', 'getDatum' ]
|
||||
);
|
||||
mockEvent = jasmine.createSpyObj(
|
||||
'event',
|
||||
[ 'preventDefault' ]
|
||||
);
|
||||
|
||||
testGrid = [ 123, 456 ];
|
||||
testModel = {
|
||||
@ -137,11 +142,6 @@ define(
|
||||
);
|
||||
});
|
||||
|
||||
it("provides styles for cells", function () {
|
||||
expect(controller.getCellStyles())
|
||||
.toEqual(jasmine.any(Array));
|
||||
});
|
||||
|
||||
it("subscribes when a domain object is available", function () {
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
findWatch("domainObject")(mockDomainObject);
|
||||
@ -266,25 +266,19 @@ define(
|
||||
expect(elements[2].value).toEqual("Formatted 31.42");
|
||||
});
|
||||
|
||||
it("adds grid cells to fill boundaries", function () {
|
||||
var s1 = {
|
||||
width: testGrid[0] * 8,
|
||||
height: testGrid[1] * 4
|
||||
},
|
||||
s2 = {
|
||||
width: testGrid[0] * 10,
|
||||
height: testGrid[1] * 6
|
||||
};
|
||||
it("updates elements styles when grid size changes", function () {
|
||||
var originalLeft;
|
||||
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.model = testModel;
|
||||
findWatch("domainObject")(mockDomainObject);
|
||||
findWatch("model.modified")(1);
|
||||
findWatch("model.composition")(mockScope.model.composition);
|
||||
|
||||
// Set first bounds
|
||||
controller.setBounds(s1);
|
||||
expect(controller.getCellStyles().length).toEqual(32); // 8 * 4
|
||||
// Set new bounds
|
||||
controller.setBounds(s2);
|
||||
expect(controller.getCellStyles().length).toEqual(60); // 10 * 6
|
||||
findWatch("model.layoutGrid")([10, 10]);
|
||||
originalLeft = controller.getElements()[0].style.left;
|
||||
findWatch("model.layoutGrid")([20, 20]);
|
||||
expect(controller.getElements()[0].style.left)
|
||||
.not.toEqual(originalLeft);
|
||||
});
|
||||
|
||||
it("listens for drop events", function () {
|
||||
@ -302,7 +296,7 @@ define(
|
||||
// Notify that a drop occurred
|
||||
testModel.composition.push('d');
|
||||
findOn('mctDrop')(
|
||||
{},
|
||||
mockEvent,
|
||||
'd',
|
||||
{ x: 300, y: 100 }
|
||||
);
|
||||
@ -310,12 +304,31 @@ define(
|
||||
// Should have added an element
|
||||
expect(testConfiguration.elements.length).toEqual(4);
|
||||
|
||||
// ...and prevented default...
|
||||
expect(mockEvent.preventDefault).toHaveBeenCalled();
|
||||
|
||||
// Should have triggered commit (provided by
|
||||
// EditRepresenter) with some message.
|
||||
expect(mockScope.commit)
|
||||
.toHaveBeenCalledWith(jasmine.any(String));
|
||||
});
|
||||
|
||||
it("ignores drops when default has been prevented", function () {
|
||||
// Avoids redundant drop-handling, WTD-1233
|
||||
mockEvent.defaultPrevented = true;
|
||||
|
||||
// Notify that a drop occurred
|
||||
testModel.composition.push('d');
|
||||
findOn('mctDrop')(
|
||||
mockEvent,
|
||||
'd',
|
||||
{ x: 300, y: 100 }
|
||||
);
|
||||
|
||||
// Should NOT have added an element
|
||||
expect(testConfiguration.elements.length).toEqual(3);
|
||||
});
|
||||
|
||||
it("unsubscribes when destroyed", function () {
|
||||
// Make an object available
|
||||
findWatch('domainObject')(mockDomainObject);
|
||||
@ -328,6 +341,7 @@ define(
|
||||
});
|
||||
|
||||
it("exposes its grid size", function () {
|
||||
findWatch('model.layoutGrid')(testGrid);
|
||||
// Template needs to be able to pass this into line
|
||||
// elements to size SVGs appropriately
|
||||
expect(controller.getGridSize()).toEqual(testGrid);
|
||||
|
71
platform/features/layout/test/LayoutCompositionPolicySpec.js
Normal file
71
platform/features/layout/test/LayoutCompositionPolicySpec.js
Normal file
@ -0,0 +1,71 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
define(
|
||||
["../src/LayoutCompositionPolicy"],
|
||||
function (LayoutCompositionPolicy) {
|
||||
"use strict";
|
||||
describe("Layout's composition policy", function () {
|
||||
var mockCandidate,
|
||||
mockContext,
|
||||
candidateType,
|
||||
contextType,
|
||||
policy;
|
||||
|
||||
beforeEach(function () {
|
||||
mockCandidate =
|
||||
jasmine.createSpyObj('candidateType', ['instanceOf']);
|
||||
mockContext =
|
||||
jasmine.createSpyObj('contextType', ['instanceOf']);
|
||||
|
||||
mockCandidate.instanceOf.andCallFake(function (t) {
|
||||
return t === candidateType;
|
||||
});
|
||||
mockContext.instanceOf.andCallFake(function (t) {
|
||||
return t === contextType;
|
||||
});
|
||||
|
||||
policy = new LayoutCompositionPolicy();
|
||||
});
|
||||
|
||||
it("disallows folders in layouts", function () {
|
||||
candidateType = 'layout';
|
||||
contextType = 'folder';
|
||||
expect(policy.allow(mockCandidate, mockContext)).toBe(false);
|
||||
});
|
||||
|
||||
it("does not disallow folders elsewhere", function () {
|
||||
candidateType = 'nonlayout';
|
||||
contextType = 'folder';
|
||||
expect(policy.allow(mockCandidate, mockContext)).toBe(true);
|
||||
});
|
||||
|
||||
it("allows things other than folders in layouts", function () {
|
||||
candidateType = 'layout';
|
||||
contextType = 'nonfolder';
|
||||
expect(policy.allow(mockCandidate, mockContext)).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -28,6 +28,7 @@ define(
|
||||
|
||||
describe("The Layout controller", function () {
|
||||
var mockScope,
|
||||
mockEvent,
|
||||
testModel,
|
||||
testConfiguration,
|
||||
controller;
|
||||
@ -37,6 +38,10 @@ define(
|
||||
"$scope",
|
||||
[ "$watch", "$on", "commit" ]
|
||||
);
|
||||
mockEvent = jasmine.createSpyObj(
|
||||
'event',
|
||||
[ 'preventDefault' ]
|
||||
);
|
||||
|
||||
testModel = {
|
||||
composition: [ "a", "b", "c" ]
|
||||
@ -144,17 +149,32 @@ define(
|
||||
// Notify that a drop occurred
|
||||
testModel.composition.push('d');
|
||||
mockScope.$on.mostRecentCall.args[1](
|
||||
{},
|
||||
mockEvent,
|
||||
'd',
|
||||
{ x: 300, y: 100 }
|
||||
);
|
||||
expect(testConfiguration.panels.d).toBeDefined();
|
||||
expect(mockEvent.preventDefault).toHaveBeenCalled();
|
||||
|
||||
// Should have triggered commit (provided by
|
||||
// EditRepresenter) with some message.
|
||||
expect(mockScope.commit)
|
||||
.toHaveBeenCalledWith(jasmine.any(String));
|
||||
});
|
||||
|
||||
it("ignores drops when default has been prevented", function () {
|
||||
// Avoids redundant drop-handling, WTD-1233
|
||||
mockEvent.defaultPrevented = true;
|
||||
|
||||
// Notify that a drop occurred
|
||||
testModel.composition.push('d');
|
||||
mockScope.$on.mostRecentCall.args[1](
|
||||
mockEvent,
|
||||
'd',
|
||||
{ x: 300, y: 100 }
|
||||
);
|
||||
expect(testConfiguration.panels.d).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -2,6 +2,7 @@
|
||||
"FixedController",
|
||||
"FixedDragHandle",
|
||||
"FixedProxy",
|
||||
"LayoutCompositionPolicy",
|
||||
"LayoutController",
|
||||
"LayoutDrag",
|
||||
"elements/AccessorMutator",
|
||||
@ -13,4 +14,4 @@
|
||||
"elements/ResizeHandle",
|
||||
"elements/TelemetryProxy",
|
||||
"elements/TextProxy"
|
||||
]
|
||||
]
|
||||
|
@ -23,7 +23,21 @@
|
||||
{
|
||||
"key": "PlotController",
|
||||
"implementation": "PlotController.js",
|
||||
"depends": [ "$scope", "telemetryFormatter", "telemetryHandler", "throttle" ]
|
||||
"depends": [
|
||||
"$scope",
|
||||
"telemetryFormatter",
|
||||
"telemetryHandler",
|
||||
"throttle",
|
||||
"PLOT_FIXED_DURATION"
|
||||
]
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"key": "PLOT_FIXED_DURATION",
|
||||
"value": 900000,
|
||||
"priority": "fallback",
|
||||
"comment": "Fifteen minutes."
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
|
@ -93,8 +93,9 @@
|
||||
|
||||
<mct-chart draw="subplot.getDrawingObject()"
|
||||
ng-mousemove="subplot.hover($event)"
|
||||
ng-mousedown="subplot.startMarquee($event)"
|
||||
ng-mouseup="subplot.endMarquee($event); plot.update()">
|
||||
mct-drag="subplot.continueDrag($event)"
|
||||
mct-drag-down="subplot.startDrag($event)"
|
||||
mct-drag-up="subplot.endDrag($event); plot.update()">
|
||||
</mct-chart>
|
||||
|
||||
<!-- TODO: Move into correct position; make part of group; infer from set of actions -->
|
||||
|
@ -52,7 +52,13 @@ define(
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function PlotController($scope, telemetryFormatter, telemetryHandler, throttle) {
|
||||
function PlotController(
|
||||
$scope,
|
||||
telemetryFormatter,
|
||||
telemetryHandler,
|
||||
throttle,
|
||||
PLOT_FIXED_DURATION
|
||||
) {
|
||||
var subPlotFactory = new SubPlotFactory(telemetryFormatter),
|
||||
modeOptions = new PlotModeOptions([], subPlotFactory),
|
||||
subplots = [],
|
||||
@ -101,7 +107,8 @@ define(
|
||||
updater = new PlotUpdater(
|
||||
handle,
|
||||
($scope.axes[0].active || {}).key,
|
||||
($scope.axes[1].active || {}).key
|
||||
($scope.axes[1].active || {}).key,
|
||||
PLOT_FIXED_DURATION
|
||||
);
|
||||
limitTracker = new PlotLimitTracker(
|
||||
handle,
|
||||
@ -170,7 +177,7 @@ define(
|
||||
|
||||
// Unsubscribe when the plot is destroyed
|
||||
$scope.$on("$destroy", releaseSubscription);
|
||||
|
||||
|
||||
// Create a throttled update function
|
||||
scheduleUpdate = throttle(function () {
|
||||
modeOptions.getModeHandler().getSubPlots()
|
||||
@ -266,4 +273,4 @@ define(
|
||||
|
||||
return PlotController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -56,6 +56,9 @@ define(
|
||||
domainOffset,
|
||||
mousePosition,
|
||||
marqueeStart,
|
||||
panStart,
|
||||
panStartBounds,
|
||||
subPlotBounds,
|
||||
hoverCoordinates,
|
||||
isHovering = false;
|
||||
|
||||
@ -88,8 +91,7 @@ define(
|
||||
// pixel coordinates in the canvas area) from a mouse
|
||||
// event object.
|
||||
function toMousePosition($event) {
|
||||
var target = $event.target,
|
||||
bounds = target.getBoundingClientRect();
|
||||
var bounds = subPlotBounds;
|
||||
|
||||
return {
|
||||
x: $event.clientX - bounds.left,
|
||||
@ -155,6 +157,25 @@ define(
|
||||
tickGenerator.generateRangeTicks(RANGE_TICKS);
|
||||
}
|
||||
|
||||
function updatePan() {
|
||||
var start, current, delta, nextOrigin;
|
||||
|
||||
// Clear the previous panning pan-zoom state
|
||||
panZoomStack.popPanZoom();
|
||||
|
||||
// Calculate what the new resulting pan-zoom should be
|
||||
start = mousePositionToDomainRange(panStart);
|
||||
current = mousePositionToDomainRange(mousePosition);
|
||||
delta = [ current[0] - start[0], current[1] - start[1] ];
|
||||
nextOrigin = [
|
||||
panStartBounds.origin[0] - delta[0],
|
||||
panStartBounds.origin[1] - delta[1]
|
||||
];
|
||||
|
||||
// ...and push a new one at the current mouse position
|
||||
panZoomStack.pushPanZoom(nextOrigin, panStartBounds.dimensions);
|
||||
}
|
||||
|
||||
|
||||
// Perform a marquee zoom.
|
||||
function marqueeZoom(start, end) {
|
||||
@ -241,31 +262,77 @@ define(
|
||||
*/
|
||||
hover: function ($event) {
|
||||
isHovering = true;
|
||||
subPlotBounds = $event.target.getBoundingClientRect();
|
||||
mousePosition = toMousePosition($event);
|
||||
updateHoverCoordinates();
|
||||
if (marqueeStart) {
|
||||
updateMarqueeBox();
|
||||
}
|
||||
if (panStart) {
|
||||
updatePan();
|
||||
updateDrawingBounds();
|
||||
updateTicks();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Continue a previously-start pan or zoom gesture.
|
||||
* @param $event the mouse event
|
||||
*/
|
||||
continueDrag: function ($event) {
|
||||
mousePosition = toMousePosition($event);
|
||||
if (marqueeStart) {
|
||||
updateMarqueeBox();
|
||||
}
|
||||
if (panStart) {
|
||||
updatePan();
|
||||
updateDrawingBounds();
|
||||
updateTicks();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Initiate a marquee zoom action.
|
||||
* @param $event the mouse event
|
||||
*/
|
||||
startMarquee: function ($event) {
|
||||
mousePosition = marqueeStart = toMousePosition($event);
|
||||
updateMarqueeBox();
|
||||
startDrag: function ($event) {
|
||||
subPlotBounds = $event.target.getBoundingClientRect();
|
||||
mousePosition = toMousePosition($event);
|
||||
// Treat any modifier key as a pan
|
||||
if ($event.altKey || $event.shiftKey || $event.ctrlKey) {
|
||||
// Start panning
|
||||
panStart = mousePosition;
|
||||
panStartBounds = panZoomStack.getPanZoom();
|
||||
// We're starting a pan, so add this back as a
|
||||
// state on the stack; it will get replaced
|
||||
// during the pan.
|
||||
panZoomStack.pushPanZoom(
|
||||
panStartBounds.origin,
|
||||
panStartBounds.dimensions
|
||||
);
|
||||
$event.preventDefault();
|
||||
} else {
|
||||
// Start marquee zooming
|
||||
marqueeStart = mousePosition;
|
||||
updateMarqueeBox();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Complete a marquee zoom action.
|
||||
* @param $event the mouse event
|
||||
*/
|
||||
endMarquee: function ($event) {
|
||||
endDrag: function ($event) {
|
||||
mousePosition = toMousePosition($event);
|
||||
subPlotBounds = undefined;
|
||||
if (marqueeStart) {
|
||||
marqueeZoom(marqueeStart, mousePosition);
|
||||
marqueeStart = undefined;
|
||||
updateMarqueeBox();
|
||||
updateDrawingBounds();
|
||||
updateTicks();
|
||||
}
|
||||
if (panStart) {
|
||||
// End panning
|
||||
panStart = undefined;
|
||||
panStartBounds = undefined;
|
||||
}
|
||||
},
|
||||
/**
|
||||
@ -311,4 +378,4 @@ define(
|
||||
return SubPlot;
|
||||
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -43,9 +43,9 @@ define(
|
||||
var mid = Math.floor((min + max) / 2),
|
||||
found = buffer[mid * 2];
|
||||
|
||||
// Collisions are not wanted
|
||||
// On collisions, insert at same index
|
||||
if (found === value) {
|
||||
return -1;
|
||||
return mid;
|
||||
}
|
||||
|
||||
// Otherwise, if we're down to a single index,
|
||||
@ -258,4 +258,4 @@ define(
|
||||
|
||||
return PlotLineBuffer;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -42,14 +42,17 @@ define(
|
||||
* @param {TelemetryHandle} handle the handle to telemetry access
|
||||
* @param {string} domain the key to use when looking up domain values
|
||||
* @param {string} range the key to use when looking up range values
|
||||
* @param {number} maxDuration maximum plot duration to display
|
||||
* @param {number} maxPoints maximum number of points to display
|
||||
*/
|
||||
function PlotUpdater(handle, domain, range, maxPoints) {
|
||||
function PlotUpdater(handle, domain, range, fixedDuration, maxPoints) {
|
||||
var ids = [],
|
||||
lines = {},
|
||||
dimensions = [0, 0],
|
||||
origin = [0, 0],
|
||||
domainExtrema,
|
||||
rangeExtrema,
|
||||
buffers = {},
|
||||
bufferArray = [],
|
||||
domainOffset;
|
||||
|
||||
@ -61,11 +64,10 @@ define(
|
||||
// Check if this set of ids matches the current set of ids
|
||||
// (used to detect if line preparation can be skipped)
|
||||
function idsMatch(nextIds) {
|
||||
return nextIds.map(function (id, index) {
|
||||
return ids[index] === id;
|
||||
}).reduce(function (a, b) {
|
||||
return a && b;
|
||||
}, true);
|
||||
return ids.length === nextIds.length &&
|
||||
nextIds.every(function (id, index) {
|
||||
return ids[index] === id;
|
||||
});
|
||||
}
|
||||
|
||||
// Prepare plot lines for this group of telemetry objects
|
||||
@ -74,7 +76,7 @@ define(
|
||||
next = {};
|
||||
|
||||
// Detect if we already have everything we need prepared
|
||||
if (ids.length === nextIds.length && idsMatch(nextIds)) {
|
||||
if (idsMatch(nextIds)) {
|
||||
// Nothing to prepare, move on
|
||||
return;
|
||||
}
|
||||
@ -88,13 +90,13 @@ define(
|
||||
|
||||
// Create buffers for these objects
|
||||
bufferArray = ids.map(function (id) {
|
||||
var buffer = new PlotLineBuffer(
|
||||
domainOffset,
|
||||
INITIAL_SIZE,
|
||||
maxPoints
|
||||
);
|
||||
next[id] = lines[id] || new PlotLine(buffer);
|
||||
return buffer;
|
||||
buffers[id] = buffers[id] || new PlotLineBuffer(
|
||||
domainOffset,
|
||||
INITIAL_SIZE,
|
||||
maxPoints
|
||||
);
|
||||
next[id] = lines[id] || new PlotLine(buffers[id]);
|
||||
return buffers[id];
|
||||
});
|
||||
}
|
||||
|
||||
@ -107,6 +109,7 @@ define(
|
||||
lines = next;
|
||||
}
|
||||
|
||||
|
||||
// Initialize the domain offset, based on these observed values
|
||||
function initializeDomainOffset(values) {
|
||||
domainOffset =
|
||||
@ -133,7 +136,7 @@ define(
|
||||
}
|
||||
|
||||
// Update dimensions and origin based on extrema of plots
|
||||
function updateExtrema() {
|
||||
function updateBounds() {
|
||||
if (bufferArray.length > 0) {
|
||||
domainExtrema = bufferArray.map(function (lineBuffer) {
|
||||
return lineBuffer.getDomainExtrema();
|
||||
@ -143,10 +146,40 @@ define(
|
||||
return lineBuffer.getRangeExtrema();
|
||||
}).reduce(reduceExtrema);
|
||||
|
||||
// Calculate best-fit dimensions
|
||||
dimensions = (rangeExtrema[0] === rangeExtrema[1]) ?
|
||||
[dimensionsOf(domainExtrema), 2.0 ] :
|
||||
[dimensionsOf(domainExtrema), dimensionsOf(rangeExtrema)];
|
||||
origin = [originOf(domainExtrema), originOf(rangeExtrema)];
|
||||
|
||||
// ...then enforce a fixed duration if needed
|
||||
if (fixedDuration !== undefined) {
|
||||
origin[0] = origin[0] + dimensions[0] - fixedDuration;
|
||||
dimensions[0] = fixedDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce maximum duration on all plot lines; not that
|
||||
// domain extrema must be up-to-date for this to behave correctly.
|
||||
function enforceDuration() {
|
||||
var cutoff;
|
||||
|
||||
function enforceDurationForBuffer(plotLineBuffer) {
|
||||
var index = plotLineBuffer.findInsertionIndex(cutoff);
|
||||
if (index > 0) {
|
||||
// Leave one point untrimmed, such that line will
|
||||
// continue off left edge of visible plot area.
|
||||
plotLineBuffer.trim(index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fixedDuration !== undefined &&
|
||||
domainExtrema !== undefined &&
|
||||
(domainExtrema[1] - domainExtrema[0] > fixedDuration)) {
|
||||
cutoff = domainExtrema[1] - fixedDuration;
|
||||
bufferArray.forEach(enforceDurationForBuffer);
|
||||
updateBounds(); // Extrema may have changed now
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,8 +213,8 @@ define(
|
||||
// Add new data
|
||||
objects.forEach(addPointFor);
|
||||
|
||||
// Finally, update extrema
|
||||
updateExtrema();
|
||||
// Then, update extrema
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
// Add historical data for this domain object
|
||||
@ -213,12 +246,12 @@ define(
|
||||
line.addSeries(series, domain, range);
|
||||
}
|
||||
|
||||
// Finally, update extrema
|
||||
updateExtrema();
|
||||
// Update extrema
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
// Use a default MAX_POINTS if none is provided
|
||||
maxPoints = maxPoints || MAX_POINTS;
|
||||
maxPoints = maxPoints !== undefined ? maxPoints : MAX_POINTS;
|
||||
|
||||
// Initially prepare state for these objects.
|
||||
// Note that this may be an empty array at this time,
|
||||
@ -290,4 +323,4 @@ define(
|
||||
return PlotUpdater;
|
||||
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -127,7 +127,7 @@ define(
|
||||
|
||||
// Simulate a marquee zoom. Note that the mockElement
|
||||
// is 100 by 100 and starts at 10,20
|
||||
subplot.startMarquee({
|
||||
subplot.startDrag({
|
||||
target: mockElement,
|
||||
clientX: 60,
|
||||
clientY: 45
|
||||
@ -137,7 +137,7 @@ define(
|
||||
clientX: 75,
|
||||
clientY: 85
|
||||
});
|
||||
subplot.endMarquee({
|
||||
subplot.endDrag({
|
||||
target: mockElement,
|
||||
clientX: 80,
|
||||
clientY: 95
|
||||
@ -162,7 +162,7 @@ define(
|
||||
|
||||
// Simulate a marquee zoom. Note that the mockElement
|
||||
// is 100 by 100 and starts at 10,20
|
||||
subplot.startMarquee({
|
||||
subplot.startDrag({
|
||||
target: mockElement,
|
||||
clientX: 60,
|
||||
clientY: 45
|
||||
@ -172,7 +172,7 @@ define(
|
||||
clientX: 75,
|
||||
clientY: 85
|
||||
});
|
||||
subplot.endMarquee({
|
||||
subplot.endDrag({
|
||||
target: mockElement,
|
||||
clientX: 60,
|
||||
clientY: 45
|
||||
@ -198,4 +198,4 @@ define(
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -83,9 +83,6 @@ define(
|
||||
expect(buffer.findInsertionIndex(10)).toEqual(4);
|
||||
expect(buffer.findInsertionIndex(14.5)).toEqual(5);
|
||||
expect(buffer.findInsertionIndex(20)).toEqual(6);
|
||||
|
||||
// 9 is already in there, disallow insertion
|
||||
expect(buffer.findInsertionIndex(9)).toEqual(-1);
|
||||
});
|
||||
|
||||
it("allows insertion in the middle", function () {
|
||||
@ -169,4 +166,4 @@ define(
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
37
platform/features/rtevents/bundle.json
Normal file
37
platform/features/rtevents/bundle.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "Event Messages",
|
||||
"description": "List of time-ordered event messages",
|
||||
"extensions": {
|
||||
"views": [
|
||||
{
|
||||
"key": "rtmessages",
|
||||
"name": "RT Messages",
|
||||
"glyph": "5",
|
||||
"description": "Scrolling list of real time messages.",
|
||||
"templateUrl": "templates/rtmessages.html",
|
||||
"needs": [ "telemetry" ],
|
||||
"delegation": true
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "RTEventListController",
|
||||
"implementation": "RTEventListController.js",
|
||||
"depends": [ "$scope", "telemetryHandler", "telemetryFormatter" ]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctRtDataTable",
|
||||
"implementation": "directives/MCTRTDataTable.js",
|
||||
"depends": [ "$window" ]
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"category": "view",
|
||||
"implementation": "policies/RTMessagesViewPolicy.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<table class="tabular">
|
||||
<thead>
|
||||
<tr>
|
||||
<th ng-repeat="header in headers">
|
||||
{{header}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="row in rows">
|
||||
<td ng-repeat="cell in row">
|
||||
{{cell}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
29
platform/features/rtevents/res/templates/rtmessages.html
Normal file
29
platform/features/rtevents/res/templates/rtmessages.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<div class="w1">
|
||||
<div class="w2"
|
||||
ng-controller="RTEventListController as rtevent">
|
||||
<mct-rt-data-table headers="rtevent.headers()" rows="rtevent.rows()" ascending-scroll="true"></mct-rt-data-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
71
platform/features/rtevents/src/DomainColumn.js
Normal file
71
platform/features/rtevents/src/DomainColumn.js
Normal file
@ -0,0 +1,71 @@
|
||||
/*****************************************************************************
|
||||
* 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,moment*/
|
||||
|
||||
/**
|
||||
* Module defining DomainColumn. Created by vwoeltje on 11/18/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A column which will report telemetry domain values
|
||||
* (typically, timestamps.) Used by the ScrollingListController.
|
||||
*
|
||||
* @constructor
|
||||
* @param domainMetadata an object with the machine- and human-
|
||||
* readable names for this domain (in `key` and `name`
|
||||
* fields, respectively.)
|
||||
* @param {TelemetryFormatter} telemetryFormatter the telemetry
|
||||
* formatting service, for making values human-readable.
|
||||
*/
|
||||
function DomainColumn(telemetryFormatter) {
|
||||
return {
|
||||
/**
|
||||
* Get the title to display in this column's header.
|
||||
* @returns {string} the title to display
|
||||
*/
|
||||
getTitle: function () {
|
||||
// At the moment there does not appear to be a way to get the
|
||||
// column's title through metadata for real time telemetry
|
||||
return "Time";
|
||||
},
|
||||
/**
|
||||
* Get the text to display inside a row under this
|
||||
* column.
|
||||
* @returns {string} the text to display
|
||||
*/
|
||||
getValue: function (domainObject, handle) {
|
||||
return {
|
||||
text: telemetryFormatter.formatDomainValue(
|
||||
handle.getDomainValue(domainObject)
|
||||
)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return DomainColumn;
|
||||
}
|
||||
);
|
138
platform/features/rtevents/src/RTEventListController.js
Normal file
138
platform/features/rtevents/src/RTEventListController.js
Normal file
@ -0,0 +1,138 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining RTEventListController.
|
||||
* Created by shale on 06/25/2014. Based on RT Scrolling lists.
|
||||
*/
|
||||
define(
|
||||
["./DomainColumn", "./RangeColumn"],
|
||||
function (DomainColumn, RangeColumn) {
|
||||
"use strict";
|
||||
|
||||
var ROW_COUNT = 100;
|
||||
|
||||
/**
|
||||
* The RTEventListController is responsible for populating
|
||||
* the contents of the messages view.
|
||||
* @constructor
|
||||
*/
|
||||
function RTEventListController($scope, telemetryHandler, telemetryFormatter) {
|
||||
var handle,
|
||||
lastUpdated = {},
|
||||
lastIds = [],
|
||||
columns = [],
|
||||
headers = [],
|
||||
rows = [];
|
||||
|
||||
function getTelemetryObjects() {
|
||||
//console.log("handle.getTelemetryObjects() ", handle.getTelemetryObjects());
|
||||
return handle ? handle.getTelemetryObjects() : [];
|
||||
}
|
||||
|
||||
function idsChanged(telemetryObjects) {
|
||||
function mismatch(id, index) {
|
||||
return id !== telemetryObjects[index].getId();
|
||||
}
|
||||
|
||||
return lastIds.length !== telemetryObjects.length ||
|
||||
lastIds.some(mismatch);
|
||||
}
|
||||
|
||||
function setupColumns(telemetryObjects) {
|
||||
var id = $scope.domainObject && $scope.domainObject.getId(),
|
||||
firstId =
|
||||
telemetryObjects[0] && telemetryObjects[0].getId();
|
||||
|
||||
columns = [];
|
||||
|
||||
columns.push(new DomainColumn(telemetryFormatter));
|
||||
columns.push(new RangeColumn());
|
||||
|
||||
headers = columns.map(function (column) {
|
||||
return column.getTitle();
|
||||
});
|
||||
}
|
||||
|
||||
function updateObjects(telemetryObjects) {
|
||||
if (idsChanged(telemetryObjects)) {
|
||||
setupColumns(telemetryObjects);
|
||||
lastIds = telemetryObjects.map(function (telemetryObject) {
|
||||
return telemetryObject.getId();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addRow(telemetryObject) {
|
||||
var id = telemetryObject.getId(),
|
||||
domainValue = handle.getDomainValue(telemetryObject);
|
||||
if (lastUpdated[id] !== domainValue &&
|
||||
domainValue !== undefined) {
|
||||
// Instead of unshift (scrolling), use push (messages)
|
||||
rows.push(columns.map(function (column) {
|
||||
return column.getValue(telemetryObject, handle).text;
|
||||
}));
|
||||
// Remove first rows when adding past the max rows limit
|
||||
rows.splice(0, rows.length - ROW_COUNT);
|
||||
lastUpdated[id] = domainValue;
|
||||
}
|
||||
}
|
||||
|
||||
function updateValues() {
|
||||
getTelemetryObjects().forEach(addRow);
|
||||
}
|
||||
|
||||
function releaseSubscription() {
|
||||
if (handle) {
|
||||
handle.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
function makeSubscription(domainObject) {
|
||||
releaseSubscription();
|
||||
rows = [];
|
||||
handle = telemetryHandler.handle(
|
||||
domainObject,
|
||||
updateValues,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
$scope.$on("$destroy", releaseSubscription);
|
||||
|
||||
$scope.$watch("domainObject", makeSubscription);
|
||||
$scope.$watch(getTelemetryObjects, updateObjects);
|
||||
|
||||
return {
|
||||
rows: function () {
|
||||
return rows;
|
||||
},
|
||||
headers: function () {
|
||||
return headers;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return RTEventListController;
|
||||
}
|
||||
);
|
68
platform/features/rtevents/src/RangeColumn.js
Normal file
68
platform/features/rtevents/src/RangeColumn.js
Normal file
@ -0,0 +1,68 @@
|
||||
/*****************************************************************************
|
||||
* 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,moment*/
|
||||
|
||||
/**
|
||||
* Module defining DomainColumn.
|
||||
* Created by vwoeltje on 11/18/14. Modified by shale on 06/25/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A column which will report telemetry range values
|
||||
* (typically, measurements.) Used by the RTEventListController.
|
||||
*
|
||||
* @constructor
|
||||
* @param rangeMetadata an object with the machine- and human-
|
||||
* readable names for this range (in `key` and `name`
|
||||
* fields, respectively.)
|
||||
* @param {TelemetryFormatter} telemetryFormatter the telemetry
|
||||
* formatting service, for making values human-readable.
|
||||
*/
|
||||
function RangeColumn() {
|
||||
return {
|
||||
/**
|
||||
* Get the title to display in this column's header.
|
||||
* @returns {string} the title to display
|
||||
*/
|
||||
getTitle: function () {
|
||||
return "Message";
|
||||
},
|
||||
/**
|
||||
* Get the text to display inside a row under this
|
||||
* column.
|
||||
* @returns {string} the text to display
|
||||
*/
|
||||
getValue: function (domainObject, handle) {
|
||||
return {
|
||||
text: handle.getRangeValue(domainObject)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return RangeColumn;
|
||||
}
|
||||
);
|
74
platform/features/rtevents/src/directives/MCTRTDataTable.js
Normal file
74
platform/features/rtevents/src/directives/MCTRTDataTable.js
Normal file
@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining MCTRTDataTable. Created by shale on 06/25/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
function MCTRTDataTable($window) {
|
||||
return {
|
||||
restrict: "E",
|
||||
templateUrl: "platform/features/rtevents/res/templates/mct-rt-data-table.html",
|
||||
scope: {
|
||||
headers: "=",
|
||||
rows: "=",
|
||||
ascendingScroll: "="
|
||||
},
|
||||
link: function ($scope, $element) {
|
||||
var currentHeight,
|
||||
previousHeight,
|
||||
scrollParent;
|
||||
|
||||
// If the scroll is set to ascending, we want to
|
||||
// check when elements are added to the table, and move the scroll
|
||||
// bar accordingly.
|
||||
// (When viewing at the bottom of the page, the scroll bar will
|
||||
// stay at the bottom despite additions to the table)
|
||||
if ($scope.ascendingScroll) {
|
||||
$scope.$watchCollection("rows", function () {
|
||||
// Wait until the page as been repainted (otherwise the
|
||||
// height will always be zero)
|
||||
$window.requestAnimationFrame(function () {
|
||||
previousHeight = currentHeight;
|
||||
// The height of the table body
|
||||
currentHeight = $element[0].firstElementChild.firstElementChild.nextElementSibling.clientHeight;
|
||||
|
||||
// One of the parents is a div that has vscroll
|
||||
scrollParent = $element[0].parentElement.parentElement.parentElement.parentElement.parentElement;
|
||||
|
||||
// Move the scrollbar down the amount that the height has changed
|
||||
scrollParent.scrollTop = scrollParent.scrollTop + (currentHeight - previousHeight);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTRTDataTable;
|
||||
}
|
||||
);
|
@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* Module defining MessagesViewPolicy. Created by shale on 06/24/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Policy controlling when the real time Messages view should be avaliable.
|
||||
* @constructor
|
||||
*/
|
||||
function RTMessagesViewPolicy() {
|
||||
|
||||
function hasStringTelemetry(domainObject) {
|
||||
var telemetry = domainObject &&
|
||||
domainObject.getCapability('telemetry'),
|
||||
metadata = telemetry ? telemetry.getMetadata() : {},
|
||||
ranges = metadata.ranges || [];
|
||||
|
||||
return ranges.some(function (range) {
|
||||
return range.format === 'string';
|
||||
});
|
||||
}
|
||||
return {
|
||||
/**
|
||||
* Check whether or not a given action is allowed by this
|
||||
* policy.
|
||||
* @param {Action} action the action
|
||||
* @param domainObject the domain object which will be viewed
|
||||
* @returns {boolean} true if not disallowed
|
||||
*/
|
||||
allow: function (view, domainObject) {
|
||||
// This policy only applies for the RT Messages view
|
||||
if (view.key === 'rtmessages') {
|
||||
// The Messages view is allowed only if the domain
|
||||
// object has string telemetry
|
||||
if (!hasStringTelemetry(domainObject)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Like all policies, allow by default.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return RTMessagesViewPolicy;
|
||||
}
|
||||
);
|
88
platform/features/rtevents/test/DomainColumnSpec.js
Normal file
88
platform/features/rtevents/test/DomainColumnSpec.js
Normal file
@ -0,0 +1,88 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* RTEventSpec. Created by vwoeltje on 11/6/14. Modified by shale on 06/25/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/DomainColumn"],
|
||||
function (DomainColumn) {
|
||||
"use strict";
|
||||
|
||||
var TEST_DOMAIN_VALUE = "some formatted domain value";
|
||||
|
||||
describe("A real time event list domain column", function () {
|
||||
var mockDomainObject,
|
||||
mockTelemetryHandler,
|
||||
mockHandle,
|
||||
mockFormatter,
|
||||
column;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getModel", "getCapability"]
|
||||
);
|
||||
mockTelemetryHandler = jasmine.createSpyObj(
|
||||
"telemetryHandler",
|
||||
["handle"]
|
||||
);
|
||||
mockHandle = jasmine.createSpyObj(
|
||||
"handle",
|
||||
["getDomainValue", "getRangeValue"]
|
||||
);
|
||||
mockFormatter = jasmine.createSpyObj(
|
||||
"formatter",
|
||||
["formatDomainValue", "formatRangeValue"]
|
||||
);
|
||||
mockFormatter.formatDomainValue.andReturn(TEST_DOMAIN_VALUE);
|
||||
|
||||
column = new DomainColumn(mockFormatter);
|
||||
});
|
||||
|
||||
it("reports the domain column header as 'Time'", function () {
|
||||
expect(column.getTitle()).toEqual("Time");
|
||||
});
|
||||
|
||||
it("retrives data from a telemetry provider", function () {
|
||||
column.getValue(mockDomainObject, mockHandle);
|
||||
expect(mockHandle.getDomainValue).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("formats domain values as time", function () {
|
||||
mockHandle.getDomainValue.andReturn(402513731000);
|
||||
|
||||
// Should have just given the value the formatter gave
|
||||
expect(column.getValue(mockDomainObject, mockHandle).text)
|
||||
.toEqual(TEST_DOMAIN_VALUE);
|
||||
|
||||
// Make sure that service interactions were as expected
|
||||
expect(mockFormatter.formatDomainValue)
|
||||
.toHaveBeenCalledWith(402513731000);
|
||||
expect(mockFormatter.formatRangeValue)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user