Compare commits

..

1 Commits

Author SHA1 Message Date
Victor Woeltjen
b3ea6612bc [Tutorials] Add hello world example 2016-12-23 15:43:45 -08:00
49 changed files with 428 additions and 1786 deletions

44
API.md
View File

@@ -129,10 +129,8 @@ provider.
The "composition" of a domain object is the list of objects it contains,
as shown (for example) in the tree for browsing. Open MCT provides a
[default solution](#default-composition-provider) for composition, but there
may be cases where you want to provide the composition of a certain object
(or type of object) dynamically.
default solution for composition, but there may be cases where you want
to provide the composition of a certain object (or type of object) dynamically.
For instance, you may want to populate a hierarchy under a custom root-level
object based on the contents of a telemetry dictionary.
To do this, you can add a new CompositionProvider:
@@ -148,29 +146,6 @@ openmct.composition.addProvider({
});
```
#### Default Composition Provider
The default composition provider applies to any domain object with
a `composition` property. The value of `composition` should be an
array of identifiers, e.g.:
```js
var domainObject = {
name: "My Object",
type: 'folder',
composition: [
{
key: '412229c3-922c-444b-8624-736d85516247',
namespace: 'foo'
},
{
key: 'd6e0ce02-5b85-4e55-8006-a8a505b64c75',
namespace: 'foo'
}
]
};
```
### Adding Telemetry Providers
When connecting to a new telemetry source, you will want to register a new
@@ -294,27 +269,12 @@ The plugin will be invoked to configure Open MCT before it is started.
Open MCT is packaged along with a few general-purpose plugins:
* `openmct.plugins.CouchDB` is an adapter for using CouchDB for persistence
of user-created objects. This is a constructor that takes the URL for the
CouchDB database as a parameter, e.g.
`openmct.install(new openmct.plugins.CouchDB('http://localhost:5984/openmct'))`
* `openmct.plugins.Elasticsearch` is an adapter for using Elasticsearch for
persistence of user-created objects. This is a
constructor that takes the URL for the Elasticsearch instance as a
parameter, e.g.
`openmct.install(new openmct.plugins.CouchDB('http://localhost:9200'))`.
Domain objects will be indexed at `/mct/domain_object`.
* `openmct.plugins.espresso` and `openmct.plugins.snow` are two different
themes (dark and light) available for Open MCT. Note that at least one
of these themes must be installed for Open MCT to appear correctly.
* `openmct.plugins.localStorage` provides persistence of user-created
objects in browser-local storage. This is particularly useful in
development environments.
* `openmct.plugins.myItems` adds a top-level folder named "My Items"
when the application is first started, providing a place for a
user to store created items.
* `openmct.plugins.utcTimeSystem` provides support for using the time
conductor with UTC time.
Generally, you will want to either install these plugins, or install
different plugins that provide persistence and an initial folder

View File

@@ -1339,6 +1339,41 @@ are supported:
Open MCT defines several Angular directives that are intended for use both
internally within the platform, and by plugins.
## Chart
The `mct-chart` directive is used to support drawing of simple charts. It is
present to support the Plot view, and its functionality is limited to the
functionality that is relevant for that view.
This directive is used at the element level and takes one attribute, `draw`
which is an Angular expression which will should evaluate to a drawing object.
This drawing object should contain the following properties:
* `dimensions`: The size, in logical coordinates, of the chart area. A
two-element array or numbers.
* `origin`: The position, in logical coordinates, of the lower-left corner of
the chart area. A two-element array or numbers.
* `lines`: An array of lines (e.g. as a plot line) to draw, where each line is
expressed as an object containing:
* `buffer`: A Float32Array containing points in the line, in logical
coordinates, in sequential x,y pairs.
* `color`: The color of the line, as a four-element RGBA array, where
each element is a number in the range of 0.0-1.0.
* `points`: The number of points in the line.
* `boxes`: An array of rectangles to draw in the chart area. Each is an object
containing:
* `start`: The first corner of the rectangle, as a two-element array of
numbers, in logical coordinates.
* `end`: The opposite corner of the rectangle, as a two-element array of
numbers, in logical coordinates. color : The color of the line, as a
four-element RGBA array, where each element is a number in the range of
0.0-1.0.
While `mct-chart` is intended to support plots specifically, it does perform
some useful management of canvas objects (e.g. choosing between WebGL and Canvas
2D APIs for drawing based on browser support) so its usage is recommended when
its supported drawing primitives are sufficient for other charting tasks.
## Container
The `mct-container` is similar to the `mct-include` directive insofar as it allows

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<script src="openmct.js"></script>
</head>
<body>
<script type="text/javascript">
openmct.install(openmct.plugins.localStorage);
openmct.install(openmct.plugins.myItems);
openmct.start();
</script>
</body>
</html>

View File

@@ -129,7 +129,7 @@ We will create this file in the directory tutorials/todo (we can hereafter refer
to this plugin as tutorials/todo as well.) We will start with an "empty bundle",
one which exposes no extensions - which looks like:
```js
```diff
define([
'openmct'
], function (
@@ -154,7 +154,7 @@ The tutorials will be updated with the new bundle registration mechanism once it
has been finalized.
#### Before
```html
```diff
<!--
Open MCT, Copyright (c) 2014-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
@@ -219,7 +219,7 @@ __index.html__
#### After
```html
```diff
<!--
Open MCT, Copyright (c) 2014-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
@@ -305,7 +305,7 @@ In the case of our to-do list feature, the to-do list itself is the thing we'll
want users to be able to create and edit. So, we will add that as a new type in
our bundle definition:
```js
```diff
define([
'openmct'
], function (
@@ -340,9 +340,8 @@ Going through the properties we've defined:
domain objects of this type.
* The `name` of "To-Do List" is the human-readable name for this type, and will
be shown to users.
* The `cssclass` maps to an icon that will be shown for each To-Do List. The icons
are defined in our [custom open MCT icon set](https://github.com/nasa/openmct/blob/master/platform/commonUI/general/res/sass/_glyphs.scss).
A complete list of available icons will be provided in the future.
* The `glyph` refers to a special character in Open MCT's custom font set;
this will be used as an icon.
* The `description` is also human-readable, and will be used whenever a longer
explanation of what this type is should be shown.
* Finally, the `features` property describes some special features of objects of
@@ -370,7 +369,7 @@ directory `tutorials/todo/res/templates` (`res` is, by default, the directory
where bundle-related resources are kept, and `templates` is where HTML templates
are stored by convention.)
```html
```diff
<div>
<a href="">All</a>
<a href="">Incomplete</a>
@@ -402,7 +401,7 @@ boolean `completed` flag.
To expose this view in Open MCT, we need to declare it in our bundle
definition:
```js
```diff
define([
'openmct'
], function (
@@ -447,7 +446,7 @@ the domain object type, but could have chosen any unique name.
domain objects of that type. This means that we'll see this view for To-do Lists
that we create, but not for other domain objects (such as Folders.)
* The `cssclass` and `name` properties describe the icon and human-readable name
* The `glyph` and `name` properties describe the icon and human-readable name
for this view to display in the UI where needed (if multiple views are available
for To-do Lists, the user will be able to choose one.)
@@ -459,7 +458,7 @@ the user to create these yet. As a temporary workaround to test the view, we
will specify an initial state for To-do List domain object models in the
definition of that type.
```js
```diff
define([
'openmct'
], function (
@@ -530,7 +529,7 @@ in the directory `tutorials/todo/src/controllers` (`src` is, by default, the
directory where bundle-related source code is kept, and controllers is where
Angular controllers are stored by convention.)
```js
```diff
define(function () {
function TodoController($scope) {
var showAll = true,
@@ -595,7 +594,7 @@ prior to our template being utilized.
On its own, this controller merely exposes these functions; the next step is to
use them from our template:
```html
```diff
+ <div ng-controller="TodoController">
<div>
+ <a ng-click="setVisibility(true)">All</a>
@@ -631,7 +630,7 @@ If we were to try to run at this point, we'd run into problems because the
`TodoController` has not been registered with Angular. We need to first declare
it in our bundle definition, as an extension of category `controllers`:
```js
```diff
define([
'openmct',
+ './src/controllers/TodoController'
@@ -725,7 +724,7 @@ An Editing user interface is typically handled in a tool bar associated with a
view. The contents of this tool bar are defined declaratively in a view's
extension definition.
```js
```diff
define([
'openmct',
'./src/controllers/TodoController'
@@ -814,7 +813,7 @@ all the applicable controls, which means no controls at all.
To support selection, we will need to make some changes to our controller:
```js
```diff
define(function () {
+ // Form to display when adding new tasks
+ var NEW_TASK_FORM = {
@@ -929,7 +928,7 @@ Additionally, we need to make changes to our template to select specific tasks
in response to some user gesture. Here, we will select tasks when a user clicks
the description.
```html
```diff
<div ng-controller="TodoController">
<div>
<a ng-click="setVisibility(true)">All</a>
@@ -955,7 +954,7 @@ __tutorials/todo/res/templates/todo.html__
Finally, the `TodoController` uses the `dialogService` now, so we need to
declare that dependency in its extension definition:
```js
```diff
define([
'openmct',
'./src/controllers/TodoController'
@@ -1059,7 +1058,7 @@ In this section, our goal is to:
To support the first two, we'll need to expose some methods for checking these
states in the controller:
```js
```diff
define(function () {
// Form to display when adding new tasks
var NEW_TASK_FORM = {
@@ -1176,7 +1175,7 @@ states visually, and to generally improve the appearance of our view. We add
another file to the res directory of our bundle; this time, it is `css/todo.css`
(with the `css` directory again being a convention.)
```css
```diff
.example-todo div.example-button-group {
margin-top: 12px;
margin-bottom: 12px;
@@ -1220,7 +1219,7 @@ To include this CSS file in our running instance of Open MCT, we need to
declare it in our bundle definition, this time as an extension of category
`stylesheets`:
```js
```diff
define([
'openmct',
'./src/controllers/TodoController'
@@ -1300,7 +1299,7 @@ To-Do List's type above; now To-Do Lists will start off empty.
Finally, let's utilize these changes from our view's template:
```html
```diff
+ <div ng-controller="TodoController" class="example-todo">
+ <div class="example-button-group">
+ <a ng-class="{ selected: checkVisibility(true) }"
@@ -1360,7 +1359,7 @@ We'll also be defining some custom styles, so we'll include that extension as
well. We'll be creating this plugin in `tutorials/bargraph`, so our initial
bundle definition looks like:
```js
```diff
define([
'openmct'
], function (
@@ -1407,7 +1406,7 @@ For this tutorial, we'll assume that we've sketched out our template and CSS
file ahead of time to describe the general look we want for the view. These
look like:
```html
```diff
<div class="example-bargraph">
<div class="example-tick-labels">
<div class="example-tick-label" style="bottom: 0%">High</div>
@@ -1458,7 +1457,7 @@ bar corresponds to which telemetry point. Inline `style` attributes are used
wherever dynamic positioning (handled by a script) is anticipated.
The corresponding CSS file which styles and positions these elements:
```css
```diff
.example-bargraph {
position: absolute;
top: 0;
@@ -1556,7 +1555,7 @@ Notably, we will not try to show telemetry data after this step.
To support this, we will add a new controller which supports our Bar Graph view:
```js
```diff
define(function () {
function BarGraphController($scope, telemetryHandler) {
var handle;
@@ -1608,7 +1607,7 @@ telemetry objects in view, as well as the width for each bar.
We will also utilize this from our template:
```html
```diff
+ <div class="example-bargraph" ng-controller="BarGraphController">
<div class="example-tick-labels">
+ <div ng-repeat="value in [low, middle, high] track by $index"
@@ -1661,7 +1660,7 @@ Finally, we expose our controller from our bundle definition. Note that the
depends declaration includes both `$scope` as well as the `telemetryHandler`
service we made use of.
```js
```diff
define([
'openmct',
'./src/controllers/BarGraphController'
@@ -1716,7 +1715,7 @@ First, let's add expose some more functionality from our controller. To make it
simple, we'll expose the top and bottom for a bar graph for a given
telemetry-providing domain object, as percentages.
```js
```diff
define(function () {
function BarGraphController($scope, telemetryHandler) {
var handle;
@@ -1768,7 +1767,7 @@ decide this.
Next, we utilize this functionality from the template:
```html
```diff
<div class="example-bargraph" ng-controller="BarGraphController">
<div class="example-tick-labels">
<div ng-repeat="value in [low, middle, high] track by $index"
@@ -1827,7 +1826,7 @@ when we return to our view later, those changes will be persisted.
First, let's add a tool bar for changing these three values in Edit mode:
```js
```diff
define([
'openmct',
'./src/controllers/BarGraphController'
@@ -1901,7 +1900,7 @@ a view proxy to work from. We will add this to our controller, and additionally
will start reading/writing those properties to the view's `configuration`
object.
```js
```diff
define(function () {
function BarGraphController($scope, telemetryHandler) {
var handle;
@@ -2024,7 +2023,7 @@ For purposes of this tutorial, a simple node server is provided to stand
in place of this existing telemetry system. It generates real-time data
and exposes it over a WebSocket connection.
```js
```diff
/*global require,process,console*/
var CONFIG = {
@@ -2206,7 +2205,7 @@ used by the server. It uses a custom format and, for purposes of example,
contains three "subsystems" containing a mix of numeric and string-based
telemetry.
```json
```diff
{
"name": "Example Spacecraft",
"identifier": "sc",
@@ -2433,7 +2432,7 @@ server. Our first step will be to add a service that will handle interactions
with the server; this will not be used by Open MCT directly, but will be
used by subsequent components we add.
```js
```diff
/*global define,WebSocket*/
define(
@@ -2488,7 +2487,7 @@ subsystems. This means that we need to convert the data from the dictionary
into domain object models, and expose these to Open MCT via a
`modelService`.
```js
```diff
/*global define*/
define(
@@ -2622,7 +2621,7 @@ This allows our telemetry dictionary to be expressed as domain object models
fix this, we will need another script which will add these subsystems to the
root-level object we added in Step 1.
```js
```diff
/*global define*/
define(
@@ -2687,7 +2686,7 @@ Finally, we wire in these changes by modifying our plugin's `bundle.js` to
provide metadata about how these pieces interact (both with each other, and
with the platform):
```js
```diff
define([
'openmct',
+ './src/ExampleTelemetryServerAdapter',
@@ -2835,7 +2834,7 @@ will do so for the server's historical telemetry.
Our first step will be to add a method to our server adapter which allows us to
send history requests to the server:
```js
```diff
/*global define,WebSocket*/
define(
@@ -2894,7 +2893,7 @@ identifier, the pending promise is resolved.
This `history` method will be used by a `telemetryService` provider which we
will implement:
```js
```diff
/*global define*/
define(
@@ -2980,7 +2979,7 @@ Finally, note that we also have a `subscribe` method, to satisfy the interface o
This script uses an `ExampleTelemetrySeries` class, which looks like:
```js
```diff
/*global define*/
define(
@@ -3012,7 +3011,7 @@ it with the interface expected by the platform (the methods shown.)
Finally, we expose this `telemetryService` provider declaratively:
```js
```diff
define([
'openmct',
'./src/ExampleTelemetryServerAdapter',
@@ -3127,7 +3126,7 @@ Finally, we want to utilize the server's ability to subscribe to telemetry
from Open MCT. To do this, first we want to expose some new methods for
this from our server adapter:
```js
```diff
/*global define,WebSocket*/
define(
@@ -3200,7 +3199,7 @@ with these subscriptions.
We then need only to utilize these methods from our `telemetryService`:
```js
```diff
/*global define*/
define(
@@ -3306,4 +3305,4 @@ server can handle this.)
Running Open MCT again, we can still plot our historical telemetry - but
now we also see that it updates in real-time as more data comes in from the
server.

View File

@@ -37,79 +37,74 @@ define([
legacyRegistry.register("example/msl", {
"name" : "Mars Science Laboratory Data Adapter",
"extensions" : {
"types": [
{
"name":"Mars Science Laboratory",
"key": "msl.curiosity",
"cssclass": "icon-object"
},
{
"name": "Instrument",
"key": "msl.instrument",
"cssclass": "icon-object",
"model": {"composition": []}
},
{
"name": "Measurement",
"key": "msl.measurement",
"cssclass": "icon-telemetry",
"model": {"telemetry": {}},
"telemetry": {
"source": "rems.source",
"domains": [
{
"name": "Time",
"key": "utc",
"format": "utc"
}
]
}
"types": [
{
"name":"Mars Science Laboratory",
"key": "msl.curiosity",
"cssclass": "icon-object"
},
{
"name": "Instrument",
"key": "msl.instrument",
"cssclass": "icon-object",
"model": {"composition": []}
},
{
"name": "Measurement",
"key": "msl.measurement",
"cssclass": "icon-telemetry",
"model": {"telemetry": {}},
"telemetry": {
"source": "rems.source",
"domains": [
{
"name": "Time",
"key": "utc",
"format": "utc"
}
]
}
],
"constants": [
{
"key": "REMS_WS_URL",
"value": "/proxyUrl?url=http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php"
}
],
"constants": [
{
"key": "REMS_WS_URL",
"value": "/proxyUrl?url=http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php"
}
],
"roots": [
{
"id": "msl:curiosity",
"priority" : "preferred",
"model": {
"type": "msl.curiosity",
"name": "Mars Science Laboratory",
"composition": ["msl_tlm:rems"]
}
],
"roots": [
{
"id": "msl:curiosity"
}
],
"models": [
{
"id": "msl:curiosity",
"priority": "preferred",
"model": {
"type": "msl.curiosity",
"name": "Mars Science Laboratory",
"composition": ["msl_tlm:rems"]
}
}
],
"services": [
{
"key":"rems.adapter",
"implementation": RemsTelemetryServerAdapter,
"depends": ["$q", "$http", "$log", "REMS_WS_URL"]
}
],
"components": [
{
"provides": "modelService",
"type": "provider",
"implementation": RemsTelemetryModelProvider,
"depends": ["rems.adapter"]
},
{
"provides": "telemetryService",
"type": "provider",
"implementation": RemsTelemetryProvider,
"depends": ["rems.adapter", "$q"]
}
]
}
}
],
"services": [
{
"key":"rems.adapter",
"implementation": RemsTelemetryServerAdapter,
"depends": ["$q", "$http", "$log", "REMS_WS_URL"]
}
],
"components": [
{
"provides": "modelService",
"type": "provider",
"implementation": RemsTelemetryModelProvider,
"depends": ["rems.adapter"]
},
{
"provides": "telemetryService",
"type": "provider",
"implementation": RemsTelemetryProvider,
"depends": ["rems.adapter", "$q"]
}
]
}
});
});

View File

@@ -33,11 +33,6 @@ define([
legacyRegistry.register("example/scratchpad", {
"extensions": {
"roots": [
{
"id": "scratch:root"
}
],
"models": [
{
"id": "scratch:root",
"model": {

View File

@@ -35,11 +35,6 @@ define([
"description": "Example illustrating the addition of a static top-level hierarchy",
"extensions": {
"roots": [
{
"id": "exampleTaxonomy"
}
],
"models": [
{
"id": "exampleTaxonomy",
"model": {

View File

@@ -32,13 +32,12 @@
[
'example/imagery',
'example/eventGenerator',
'example/generator'
'example/generator',
'platform/features/my-items',
'platform/persistence/local'
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.myItems);
openmct.install(openmct.plugins.localStorage);
openmct.install(openmct.plugins.espresso);
openmct.start();
});
</script>

View File

@@ -76,7 +76,7 @@ module.exports = function(config) {
// Specify browsers to run tests in.
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'Chrome'
'PhantomJS'
],
// Code coverage reporting.

View File

@@ -25,12 +25,13 @@
"jsdoc": "^3.3.2",
"jshint": "^2.7.0",
"karma": "^0.13.3",
"karma-chrome-launcher": "^0.1.12",
"karma-chrome-launcher": "^0.1.8",
"karma-cli": "0.0.4",
"karma-coverage": "^0.5.3",
"karma-html-reporter": "^0.2.7",
"karma-jasmine": "^0.1.5",
"karma-junit-reporter": "^0.3.8",
"karma-phantomjs-launcher": "^1.0.0",
"karma-requirejs": "^0.2.2",
"lodash": "^3.10.1",
"markdown-toc": "^0.11.7",
@@ -39,6 +40,7 @@
"mkdirp": "^0.5.1",
"moment": "^2.11.1",
"node-bourbon": "^4.2.3",
"phantomjs-prebuilt": "2.1.11 || >2.1.12 <3.0.0",
"requirejs": "2.1.x",
"split": "^1.0.0"
},

View File

@@ -20,7 +20,7 @@
at runtime from the About dialog for additional information.
-->
<div ng-controller="BrowseObjectController" class="abs l-flex-col">
<div class="holder flex-elem l-flex-row object-browse-bar">
<div class="holder flex-elem l-flex-row object-browse-bar ">
<div class="items-select left flex-elem l-flex-row grows">
<mct-representation key="'back-arrow'"
mct-object="domainObject"
@@ -31,18 +31,16 @@
</mct-representation>
</div>
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
<span class="l-object-action-buttons">
<mct-representation key="'switcher'"
mct-object="domainObject"
ng-model="representation">
</mct-representation>
<!-- Temporarily, on mobile, the action buttons are hidden-->
<mct-representation key="'action-group'"
mct-object="domainObject"
parameters="{ category: 'view-control' }"
class="mobile-hide l-object-action-buttons">
</mct-representation>
</span>
<mct-representation key="'switcher'"
mct-object="domainObject"
ng-model="representation">
</mct-representation>
<!-- Temporarily, on mobile, the action buttons are hidden-->
<mct-representation key="'action-group'"
mct-object="domainObject"
parameters="{ category: 'view-control' }"
class="mobile-hide">
</mct-representation>
</div>
</div>
<div class="holder l-flex-col flex-elem grows l-object-wrapper l-controls-visible l-time-controller-visible">

View File

@@ -28,8 +28,4 @@
key="'menu-arrow'"
mct-object='domainObject'
class="flex-elem context-available-w"></mct-representation>
</span>
<a class="s-button icon-expand t-btn-view-large"
title="View large"
mct-trigger-modal>
</a>
</span>

View File

@@ -53,8 +53,7 @@ define([
"depends": [
"overlayService",
"$q",
"$log",
"$document"
"$log"
]
},
{

View File

@@ -19,7 +19,7 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="abs overlay l-dialog" ng-class="{'delayEntry100ms' : ngModel.delay}">
<div class="abs overlay" ng-class="{'delayEntry100ms' : ngModel.delay}">
<div class="abs blocker"></div>
<div class="abs holder">
<a ng-click="ngModel.cancel()"

View File

@@ -35,15 +35,11 @@ define(
* @memberof platform/commonUI/dialog
* @constructor
*/
function DialogService(overlayService, $q, $log, $document) {
function DialogService(overlayService, $q, $log) {
this.overlayService = overlayService;
this.$q = $q;
this.$log = $log;
this.activeOverlay = undefined;
this.findBody = function () {
return $document.find('body');
};
}
/**
@@ -64,8 +60,7 @@ define(
// input is asynchronous.
var deferred = this.$q.defer(),
self = this,
overlay,
handleEscKeydown;
overlay;
// Confirm function; this will be passed in to the
// overlay-dialog template and associated with a
@@ -81,22 +76,13 @@ define(
// Cancel or X button click
function cancel() {
deferred.reject();
self.findBody().off('keydown', handleEscKeydown);
self.dismissOverlay(overlay);
}
handleEscKeydown = function (event) {
if (event.keyCode === 27) {
cancel();
}
};
// Add confirm/cancel callbacks
model.confirm = confirm;
model.cancel = cancel;
this.findBody().on('keydown', handleEscKeydown);
if (this.canShowDialog(model)) {
// Add the overlay using the OverlayService, which
// will handle actual insertion into the DOM

View File

@@ -33,8 +33,6 @@ define(
mockLog,
mockOverlay,
mockDeferred,
mockDocument,
mockBody,
dialogService;
beforeEach(function () {
@@ -58,13 +56,6 @@ define(
"deferred",
["resolve", "reject"]
);
mockDocument = jasmine.createSpyObj(
"$document",
["find"]
);
mockBody = jasmine.createSpyObj('body', ['on', 'off']);
mockDocument.find.andReturn(mockBody);
mockDeferred.promise = "mock promise";
mockQ.defer.andReturn(mockDeferred);
@@ -73,8 +64,7 @@ define(
dialogService = new DialogService(
mockOverlayService,
mockQ,
mockLog,
mockDocument
mockLog
);
});
@@ -140,36 +130,6 @@ define(
);
});
it("adds a keydown event listener to the body", function () {
dialogService.getUserInput({}, {});
expect(mockDocument.find).toHaveBeenCalledWith("body");
expect(mockBody.on).toHaveBeenCalledWith("keydown", jasmine.any(Function));
});
it("destroys the event listener when the dialog is cancelled", function () {
dialogService.getUserInput({}, {});
mockOverlayService.createOverlay.mostRecentCall.args[1].cancel();
expect(mockBody.off).toHaveBeenCalledWith("keydown", jasmine.any(Function));
});
it("cancels the dialog when an escape keydown event is triggered", function () {
dialogService.getUserInput({}, {});
mockBody.on.mostRecentCall.args[1]({
keyCode: 27
});
expect(mockDeferred.reject).toHaveBeenCalled();
expect(mockDeferred.resolve).not.toHaveBeenCalled();
});
it("ignores non escape keydown events", function () {
dialogService.getUserInput({}, {});
mockBody.on.mostRecentCall.args[1]({
keyCode: 13
});
expect(mockDeferred.reject).not.toHaveBeenCalled();
expect(mockDeferred.resolve).not.toHaveBeenCalled();
});
describe("the blocking message dialog", function () {
var dialogModel = {};
var dialogHandle;

View File

@@ -1,8 +1,8 @@
{
"metadata": {
"name": "openmct-symbols-16px",
"lastOpened": 1487197651675,
"created": 1487194069058
"lastOpened": 1481575258437,
"created": 1481575255265
},
"iconSets": [
{
@@ -540,21 +540,13 @@
"code": 921654,
"tempChar": ""
},
{
"order": 120,
"id": 105,
"name": "icon-reset",
"prevSize": 24,
"code": 921655,
"tempChar": ""
},
{
"order": 121,
"id": 103,
"name": "icon-x-in-circle",
"prevSize": 24,
"code": 921656,
"tempChar": ""
"tempChar": ""
},
{
"order": 118,
@@ -562,7 +554,7 @@
"name": "icon-brightness",
"prevSize": 24,
"code": 921657,
"tempChar": ""
"tempChar": ""
},
{
"order": 119,
@@ -570,15 +562,15 @@
"name": "icon-contrast",
"prevSize": 24,
"code": 921664,
"tempChar": ""
"tempChar": ""
},
{
"order": 122,
"id": 106,
"name": "icon-expand",
"order": 120,
"id": 105,
"name": "icon-reset",
"prevSize": 24,
"code": 921665,
"tempChar": ""
"code": 921655,
"tempChar": ""
},
{
"order": 37,
@@ -586,7 +578,7 @@
"name": "icon-activity",
"id": 32,
"code": 921856,
"tempChar": ""
"tempChar": ""
},
{
"order": 36,
@@ -594,7 +586,7 @@
"name": "icon-activity-mode",
"id": 31,
"code": 921857,
"tempChar": ""
"tempChar": ""
},
{
"order": 52,
@@ -602,7 +594,7 @@
"name": "icon-autoflow-tabular",
"id": 47,
"code": 921858,
"tempChar": ""
"tempChar": ""
},
{
"order": 55,
@@ -610,7 +602,7 @@
"name": "icon-clock",
"id": 50,
"code": 921859,
"tempChar": ""
"tempChar": ""
},
{
"order": 58,
@@ -618,7 +610,7 @@
"name": "icon-database",
"id": 53,
"code": 921860,
"tempChar": ""
"tempChar": ""
},
{
"order": 57,
@@ -626,7 +618,7 @@
"name": "icon-database-query",
"id": 52,
"code": 921861,
"tempChar": ""
"tempChar": ""
},
{
"order": 17,
@@ -634,7 +626,7 @@
"name": "icon-dataset",
"id": 12,
"code": 921862,
"tempChar": ""
"tempChar": ""
},
{
"order": 22,
@@ -642,7 +634,7 @@
"name": "icon-datatable",
"id": 17,
"code": 921863,
"tempChar": ""
"tempChar": ""
},
{
"order": 59,
@@ -650,7 +642,7 @@
"name": "icon-dictionary",
"id": 54,
"code": 921864,
"tempChar": ""
"tempChar": ""
},
{
"order": 62,
@@ -658,7 +650,7 @@
"name": "icon-folder",
"id": 57,
"code": 921865,
"tempChar": ""
"tempChar": ""
},
{
"order": 66,
@@ -666,7 +658,7 @@
"name": "icon-image",
"id": 61,
"code": 921872,
"tempChar": ""
"tempChar": ""
},
{
"order": 68,
@@ -674,7 +666,7 @@
"name": "icon-layout",
"id": 63,
"code": 921873,
"tempChar": ""
"tempChar": ""
},
{
"order": 77,
@@ -682,7 +674,7 @@
"name": "icon-object",
"id": 72,
"code": 921874,
"tempChar": ""
"tempChar": ""
},
{
"order": 78,
@@ -690,7 +682,7 @@
"name": "icon-object-unknown",
"id": 73,
"code": 921875,
"tempChar": ""
"tempChar": ""
},
{
"order": 79,
@@ -698,7 +690,7 @@
"name": "icon-packet",
"id": 74,
"code": 921876,
"tempChar": ""
"tempChar": ""
},
{
"order": 80,
@@ -706,7 +698,7 @@
"name": "icon-page",
"id": 75,
"code": 921877,
"tempChar": ""
"tempChar": ""
},
{
"order": 114,
@@ -714,7 +706,7 @@
"name": "icon-plot-overlay",
"prevSize": 24,
"code": 921878,
"tempChar": ""
"tempChar": ""
},
{
"order": 113,
@@ -722,7 +714,7 @@
"name": "icon-plot-stacked",
"prevSize": 24,
"code": 921879,
"tempChar": ""
"tempChar": ""
},
{
"order": 10,
@@ -730,7 +722,7 @@
"name": "icon-session",
"id": 5,
"code": 921880,
"tempChar": ""
"tempChar": ""
},
{
"order": 24,
@@ -738,7 +730,7 @@
"name": "icon-tabular",
"id": 19,
"code": 921881,
"tempChar": ""
"tempChar": ""
},
{
"order": 7,
@@ -746,7 +738,7 @@
"name": "icon-tabular-lad",
"id": 2,
"code": 921888,
"tempChar": ""
"tempChar": ""
},
{
"order": 6,
@@ -754,7 +746,7 @@
"name": "icon-tabular-lad-set",
"id": 1,
"code": 921889,
"tempChar": ""
"tempChar": ""
},
{
"order": 8,
@@ -762,7 +754,7 @@
"name": "icon-tabular-realtime",
"id": 3,
"code": 921890,
"tempChar": ""
"tempChar": ""
},
{
"order": 23,
@@ -770,7 +762,7 @@
"name": "icon-tabular-scrolling",
"id": 18,
"code": 921891,
"tempChar": ""
"tempChar": ""
},
{
"order": 112,
@@ -778,7 +770,7 @@
"name": "icon-telemetry",
"id": 86,
"code": 921892,
"tempChar": ""
"tempChar": ""
},
{
"order": 90,
@@ -786,7 +778,7 @@
"name": "icon-telemetry-panel",
"id": 85,
"code": 921893,
"tempChar": ""
"tempChar": ""
},
{
"order": 93,
@@ -794,7 +786,7 @@
"name": "icon-timeline",
"id": 88,
"code": 921894,
"tempChar": ""
"tempChar": ""
},
{
"order": 116,
@@ -802,7 +794,7 @@
"name": "icon-timer-v1.5",
"prevSize": 24,
"code": 921895,
"tempChar": ""
"tempChar": ""
},
{
"order": 11,
@@ -810,7 +802,7 @@
"name": "icon-topic",
"id": 6,
"code": 921896,
"tempChar": ""
"tempChar": ""
},
{
"order": 115,
@@ -818,7 +810,7 @@
"name": "icon-box-with-dashed-lines",
"id": 29,
"code": 921897,
"tempChar": ""
"tempChar": ""
}
],
"metadata": {
@@ -2191,30 +2183,6 @@
]
}
},
{
"id": 104,
"paths": [
"M460.8 460.8l-187.8-187.8c57.2-42.8 128-68.2 204.8-68.2 188.2 0 341.6 153.2 341.6 341.4s-153.2 341.2-341.4 341.2c-165 0-302.8-117.6-334.6-273h-138.4c14.2 101.8 61 195.6 135 269.6 90.2 90.2 210.4 140 338 140s247.6-49.8 338-140 140-210.4 140-338-49.8-247.6-140-338-210.4-140-338-140c-111.4 0-217 38-302 107.6l-176-175.6v460.8h460.8z"
],
"attrs": [
{
"fill": "rgb(0, 161, 75)"
}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-reset"
],
"colorPermutations": {
"1161751207457516161751": [
{
"f": 1
}
]
}
},
{
"paths": [
"M512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512zM832 704l-128 128-192-192-192 192-128-128 192-192-192-192 128-128 192 192 192-192 128 128-192 192 192 192z"
@@ -2335,31 +2303,26 @@
}
},
{
"id": 106,
"id": 104,
"paths": [
"M960 0c0 0 0 0 0 0h-320v128h165.4l-210.6 210.8c-25 25-25 65.6 0 90.6 12.4 12.4 28.8 18.8 45.2 18.8s32.8-6.2 45.2-18.8l210.8-210.8v165.4h128v-384h-64z",
"M896 805.4l-210.8-210.6c-25-25-65.6-25-90.6 0s-25 65.6 0 90.6l210.8 210.6h-165.4v128h384v-384h-128v165.4z",
"M218.6 128h165.4v-128h-320c0 0 0 0 0 0h-64v384h128v-165.4l210.8 210.8c12.4 12.4 28.8 18.8 45.2 18.8s32.8-6.2 45.2-18.8c25-25 25-65.6 0-90.6l-210.6-210.8z",
"M338.8 594.8l-210.8 210.6v-165.4h-128v384h384v-128h-165.4l210.8-210.8c25-25 25-65.6 0-90.6-25.2-24.8-65.6-24.8-90.6 0.2z"
"M460.8 460.8l-187.8-187.8c57.2-42.8 128-68.2 204.8-68.2 188.2 0 341.6 153.2 341.6 341.4s-153.2 341.2-341.4 341.2c-165 0-302.8-117.6-334.6-273h-138.4c14.2 101.8 61 195.6 135 269.6 90.2 90.2 210.4 140 338 140s247.6-49.8 338-140 140-210.4 140-338-49.8-247.6-140-338-210.4-140-338-140c-111.4 0-217 38-302 107.6l-176-175.6v460.8h460.8z"
],
"attrs": [
{},
{},
{},
{}
],
"grid": 16,
"tags": [
"icon-expand"
{
"fill": "rgb(0, 161, 75)"
}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-reset"
],
"colorPermutations": {
"1161751207457516161751": [
{},
{},
{},
{}
{
"f": 1
}
]
}
},

View File

@@ -77,7 +77,6 @@
<glyph unicode="&#xe1038;" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
<glyph unicode="&#xe1039;" glyph-name="icon-brightness" d="M253.414 641.939l-155.172 116.384c-50.233-66.209-85.127-146.713-97.91-234.39l191.586-30.216c8.145 56.552 29.998 106.879 62.068 149.006zM191.98 402.283l-191.919-27.434c13.115-90.459 48.009-170.963 99.174-238.453l154.18 117.665c-31.476 41.347-53.309 91.675-61.231 146.504zM466.283 768.020l-27.434 191.919c-90.459-13.115-170.963-48.009-238.453-99.174l117.665-154.18c41.347 31.476 91.675 53.309 146.504 61.231zM822.323 861.758c-66.209 50.233-146.713 85.127-234.39 97.91l-30.216-191.586c56.552-8.145 106.879-29.998 149.006-62.068zM832.020 493.717l191.919 27.434c-13.115 90.459-48.009 170.963-99.174 238.453l-154.18-117.665c31.476-41.347 53.309-91.675 61.231-146.504zM201.677 34.242c66.209-50.233 146.713-85.127 234.39-97.91l30.216 191.586c-56.552 8.145-106.879 29.998-149.006 62.068zM770.586 254.061l155.131-116.343c50.233 66.209 85.127 146.713 97.91 234.39l-191.586 30.216c-8.125-56.564-29.966-106.906-62.028-149.049zM557.717 127.98l27.434-191.919c90.459 13.115 170.963 48.009 238.453 99.174l-117.665 154.18c-41.347-31.476-91.675-53.309-146.504-61.231zM770.586 448c0-142.813-115.773-258.586-258.586-258.586s-258.586 115.773-258.586 258.586c0 142.813 115.773 258.586 258.586 258.586s258.586-115.773 258.586-258.586z" />
<glyph unicode="&#xe1040;" glyph-name="icon-contrast" d="M512 960c-282.78 0-512-229.24-512-512s229.22-512 512-512 512 229.24 512 512-229.22 512-512 512zM783.52 176.48c-69.111-69.481-164.785-112.481-270.502-112.481-0.358 0-0.716 0-1.074 0.001l0.055 768c212.070-0.010 383.982-171.929 383.982-384 0-106.034-42.977-202.031-112.462-271.52z" />
<glyph unicode="&#xe1041;" glyph-name="icon-expand" d="M960 960c0 0 0 0 0 0h-320v-128h165.4l-210.6-210.8c-25-25-25-65.6 0-90.6 12.4-12.4 28.8-18.8 45.2-18.8s32.8 6.2 45.2 18.8l210.8 210.8v-165.4h128v384h-64zM896 154.6l-210.8 210.6c-25 25-65.6 25-90.6 0s-25-65.6 0-90.6l210.8-210.6h-165.4v-128h384v384h-128v-165.4zM218.6 832h165.4v128h-320c0 0 0 0 0 0h-64v-384h128v165.4l210.8-210.8c12.4-12.4 28.8-18.8 45.2-18.8s32.8 6.2 45.2 18.8c25 25 25 65.6 0 90.6l-210.6 210.8zM338.8 365.2l-210.8-210.6v165.4h-128v-384h384v128h-165.4l210.8 210.8c25 25 25 65.6 0 90.6-25.2 24.8-65.6 24.8-90.6-0.2z" />
<glyph unicode="&#xe1100;" glyph-name="icon-activity" 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="&#xe1101;" glyph-name="icon-activity-mode" 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="&#xe1102;" glyph-name="icon-autoflow-tabular" 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" />

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -66,7 +66,7 @@ body, html {
color: $colorBodyFg;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 100%;
font-weight: normal;
font-weight: 200;
height: 100%;
width: 100%;
}

View File

@@ -73,11 +73,10 @@ $glyph-icon-thumbs-strip: '\e1033';
$glyph-icon-two-parts-both: '\e1034';
$glyph-icon-two-parts-one-only: '\e1035';
$glyph-icon-resync: '\e1036';
$glyph-icon-reset: '\e1037';
$glyph-icon-x-in-circle: '\e1038';
$glyph-icon-brightness: '\e1039';
$glyph-icon-contrast: '\e1040';
$glyph-icon-expand: '\e1041';
$glyph-icon-reset: '\e1037';
$glyph-icon-activity: '\e1100';
$glyph-icon-activity-mode: '\e1101';
$glyph-icon-autoflow-tabular: '\e1102';
@@ -176,12 +175,11 @@ $glyph-icon-box-with-dashed-lines: '\e1129';
.icon-thumbs-strip { @include glyph($glyph-icon-thumbs-strip); }
.icon-two-parts-both { @include glyph($glyph-icon-two-parts-both); }
.icon-two-parts-one-only { @include glyph($glyph-icon-two-parts-one-only); }
.icon-resync { @include glyph($glyph-icon-resync); }
.icon-reset { @include glyph($glyph-icon-reset); }
.icon-x-in-circle { @include glyph($glyph-icon-x-in-circle); }
.icon-brightness { @include glyph($glyph-icon-brightness); }
.icon-contrast { @include glyph($glyph-icon-contrast); }
.icon-expand { @include glyph($glyph-icon-expand); }
.icon-reset { @include glyph($glyph-icon-reset); }
.icon-resync { @include glyph($glyph-icon-resync); }
.icon-activity { @include glyph($glyph-icon-activity); }
.icon-activity-mode { @include glyph($glyph-icon-activity-mode); }
.icon-autoflow-tabular { @include glyph($glyph-icon-autoflow-tabular); }

View File

@@ -631,8 +631,7 @@ textarea {
}
}
.view-switcher,
.t-btn-view-large {
.view-switcher {
@include trans-prop-nice-fade($controlFadeMs);
}

View File

@@ -249,7 +249,7 @@
.context-menu-holder,
.menu-holder {
position: absolute;
z-index: 120;
z-index: 70;
.context-menu-wrapper {
position: absolute;
height: 100%;
@@ -273,7 +273,7 @@
.btn-bar.right .menu,
.menus-to-left .menu {
z-index: 79;
z-index: 79;
left: auto;
right: 0;
width: auto;

View File

@@ -21,16 +21,11 @@
*****************************************************************************/
.overlay {
font-size: 90%;
&.delayEntry100ms {
@include keyframes(fadeInFromNone) {
0% {
display: none;
opacity: 0;
}
100% {
display: block;
opacity: 1;
}
0% { display: none; opacity: 0; }
100% { display: block; opacity: 1; }
}
@include animation-delay($delayEntryMs);
@include animation(fadeInFromNone $durEntryMs ease-in);
@@ -48,15 +43,21 @@
left: auto;
z-index: 100;
}
> .holder {
@include containerSubtle($colorOvrBg, $colorOvrFg);
border-radius: $basicCr * 3;
color: $colorOvrFg;
top: 50%;
right: auto;
bottom: auto;
left: 50%;
@include transform(translateX(-50%) translateY(-50%));
height: 70%;
width: 50%;
min-height: 300px;
max-height: 800px;
min-width: 600px;
max-width: 1000px;
z-index: 101;
> .contents {
$m: $overlayMargin;
@@ -66,106 +67,72 @@
left: $m;
}
}
}
.title {
@include ellipsize();
font-size: 1.2em;
line-height: 120%;
margin-bottom: $interiorMargin;
}
.overlay {
&.l-dialog {
.s-button {
&:not(.major) {
@include btnSubtle($bg: $colorOvrBtnBg, $bgHov: pullForward($colorOvrBtnBg, 10%), $fg: $colorOvrBtnFg, $fgHov: $colorOvrBtnFg, $ic: $colorOvrBtnFg, $icHov: $colorOvrBtnFg);
.hint, .field-hints { color: $colorFieldHintOverlay !important; }
.abs.top-bar {
height: $ovrTopBarH;
}
.abs.editor,
.abs.message-body {
top: $ovrTopBarH + $interiorMarginLg;
bottom: $ovrFooterH + $interiorMarginLg;
left: 0;
right: 0;
overflow: auto;
.field.l-input-med {
input[type='text'] {
width: 100%;
}
}
> .holder {
@include containerSubtle($colorOvrBg, $colorOvrFg);
border-radius: $basicCr * 2;
//color: $colorOvrFg;
height: 70%;
width: 50%;
}
.title {
@include ellipsize();
font-size: 1.2em;
line-height: 120%;
margin-bottom: $interiorMargin;
}
.hint, .field-hints {
color: $colorFieldHintOverlay !important;
}
.abs.top-bar {
height: $ovrTopBarH;
}
.abs.bottom-bar {
top: auto;
right: 0;
bottom: 0;
left: 0;
overflow: visible;
height: $ovrFooterH;
}
.abs.editor,
.abs.message-body {
top: $ovrTopBarH + $interiorMarginLg;
bottom: $ovrFooterH + $interiorMarginLg;
left: 0;
right: 0;
overflow: auto;
.field.l-input-med {
input[type='text'] {
width: 100%;
}
}
}
.bottom-bar {
text-align: right;
.s-button {
font-size: 95%;
height: $ovrFooterH;
line-height: $ovrFooterH;
margin-left: $interiorMargin;
padding: 0 $interiorMargin * 3;
&:first-child {
margin-left: 0;
}
}
}
.l-progress-bar {
$h: $progressBarHOverlay;
display: block;
height: $h;
line-height: $h;
margin: .5em 0;
width: 100%;
}
.select {
box-shadow: $shdwBtnsOverlay;
}
}
&.l-large-view {
> .holder {
@include keyframes(overlayIn) {
from { opacity: 0; width: 1%; height: 1%; }
to { opacity: 1; width: 90%; height: 90%; }
.bottom-bar {
text-align: right;
.s-button {
$bg: $colorOvrBtnBg;
&:not(.major) {
@include btnSubtle($bg, pullForward($bg, 10%), $colorOvrBtnFg, $colorOvrBtnFg);
}
@include animToParams(overlayIn, $dur: 1s, $delay: 0);
background: $colorBodyBg;
border-radius: $basicCr * 2;
//height: 90%;
//width: 90%;
.t-btn-view-large {
display: none;
font-size: 95%;
height: $ovrFooterH;
line-height: $ovrFooterH;
margin-left: $interiorMargin;
padding: 0 $interiorMargin * 3;
&:first-child {
margin-left: 0;
}
}
}
.abs.bottom-bar {
top: auto;
right: 0;
bottom: 0;
left: 0;
overflow: visible;
height: $ovrFooterH;
}
.l-progress-bar {
$h: $progressBarHOverlay;
display: block;
height: $h;
line-height: $h;
margin: .5em 0;
width: 100%;
}
.select {
box-shadow: $shdwBtnsOverlay;
}
}
@@ -174,4 +141,4 @@
$h: 225px;
min-height: $h;
height: $h;
}
}

View File

@@ -20,77 +20,69 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
.frame {
$ohH: $btnFrameH;
$bc: $colorInteriorBorder;
&.child-frame.panel {
background: $colorBodyBg;
border: 1px solid $bc;
$ohH: $btnFrameH;
$bc: $colorInteriorBorder;
&.child-frame.panel {
background: $colorBodyBg;
border: 1px solid $bc;
z-index: 0; // Needed to prevent child-frame controls from showing through when another child-frame is above
&:hover {
border-color: lighten($bc, 10%);
&:hover {
border-color: lighten($bc, 10%);
}
}
.object-top-bar {
font-size: 0.75em;
height: $ohH;
line-height: $ohH;
.left {
padding-right: $interiorMarginLg;
}
}
.object-browse-bar {
font-size: 0.75em;
height: $ohH;
line-height: $ohH;
}
> .object-holder.abs {
top: $ohH + $interiorMargin;
}
.contents {
$myM: $interiorMargin;
top: $myM;
right: $myM;
bottom: $myM;
left: $myM;
}
&.frame-template {
.s-button,
.s-menu-button {
height: $ohH;
line-height: $ohH;
padding: 0 $interiorMargin;
> span,
}
>.object-holder.abs {
top: $ohH + $interiorMargin;
}
.contents {
$myM: $interiorMargin;
top: $myM;
right: $myM;
bottom: $myM;
left: $myM;
}
&.frame-template {
.s-button,
.s-menu-button {
height: $ohH;
line-height: $ohH;
padding: 0 $interiorMargin;
> span,
&:before {
font-size: 0.65rem;
}
}
font-size: 0.65rem;
}
}
.s-menu-button:after {
font-size: 8px;
}
.s-menu-button:after {
font-size: 8px;
}
.view-switcher {
z-index: 10;
}
}
.view-switcher {
margin-left: $interiorMargin; // Kick other top bar elements away when I'm present.
// Hide the name when the view switcher is in a frame context
.title-label {
display: none;
}
}
.view-switcher {
z-index: 10;
}
}
.view-switcher {
// Hide the name when the view switcher is in a frame context
.title-label {
display: none;
}
}
}
body.desktop .frame {
// Hide local controls initially and show it them on hover when they're in an element that's in a frame context
// Frame template is used because we need to target the lowest nested frame
.view-switcher,
.t-btn-view-large {
opacity: 0;
pointer-events: none;
}
// Target the first descendant so that we only show the elements in the outermost container.
// Handles the case where we have layouts in layouts.
&:hover > .object-browse-bar {
.view-switcher,
.t-btn-view-large {
opacity: 1;
pointer-events: inherit;
}
}
}
body.desktop .frame.frame-template {
// Hide the view switcher by default when it's in an element that's in a frame context
// Frame template is used because we need to target the lowest nested frame
.view-switcher {
opacity: 0;
}
&:hover .view-switcher {
// Show the view switcher on frame hover
opacity: 1;
}
}

View File

@@ -136,6 +136,14 @@
.mini-tab-icon.toggle-pane {
z-index: 5;
}
&.items {
.object-browse-bar {
.left.abs,
.right.abs {
top: auto;
}
}
}
}
body.desktop .pane .mini-tab-icon.toggle-pane {
@@ -242,9 +250,10 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
vertical-align: top;
}
.object-browse-bar {
.l-object-action-buttons {
margin-left: $interiorMarginLg; // Kick the view switcher and other elements away
.object-browse-bar,
.top-bar {
.view-switcher {
margin-right: $interiorMarginLg * 2;
}
}
@@ -256,6 +265,7 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
white-space: nowrap;
.left {
padding-right: $interiorMarginLg;
.l-back {
margin-right: $interiorMarginLg;
&.s-status-editing { display: none; }
@@ -338,7 +348,7 @@ body.desktop {
.pane:not(.resizing) {
@include trans-prop-nice-resize-w(250ms);
}
.pane.primary-pane > .object-browse-bar {
.pane.primary-pane .object-browse-bar {
min-width: 200px; // Needed for nice display when primary pane is constrained severely via splitters
}
}

View File

@@ -24,7 +24,6 @@ define([
"./src/LayoutController",
"./src/FixedController",
"./src/LayoutCompositionPolicy",
'./src/MCTTriggerModal',
"text!./res/templates/layout.html",
"text!./res/templates/fixed.html",
"text!./res/templates/frame.html",
@@ -38,7 +37,6 @@ define([
LayoutController,
FixedController,
LayoutCompositionPolicy,
MCTTriggerModal,
layoutTemplate,
fixedTemplate,
frameTemplate,
@@ -224,15 +222,6 @@ define([
"template": frameTemplate
}
],
"directives": [
{
"key": "mctTriggerModal",
"implementation": MCTTriggerModal,
"depends": [
"$document"
]
}
],
"controllers": [
{
"key": "LayoutController",

View File

@@ -20,7 +20,7 @@
at runtime from the About dialog for additional information.
-->
<div class="frame frame-template abs">
<div class="abs object-browse-bar l-flex-row">
<div class="abs object-top-bar l-flex-row">
<div class="left flex-elem l-flex-row grows">
<mct-representation
key="'object-header'"

View File

@@ -1,106 +0,0 @@
define([
], function () {
var OVERLAY_TEMPLATE = '' +
'<div class="abs overlay l-large-view">' +
' <div class="abs blocker"></div>' +
' <div class="abs holder">' +
' <a class="close icon-x"></a>' +
' <div class="abs contents"></div>' +
' </div>' +
'</div>';
/**
* MCT Trigger Modal is intended for use in only one location: inside the
* object-header to allow views in a layout to be popped out in a modal.
* Users can close the modal and go back to normal, and everything generally
* just works fine.
*
* This code is sensitive to how our html is constructed-- particularly with
* how it locates the the container of an element in a layout. However, it
* should be able to handle slight relocations so long as it is always a
* descendent of a `.frame` element.
*/
function MCTTriggerModal() {
function link($scope, $element) {
var frame = $element.parent();
for (var i = 0; i < 10; i++) {
if (frame.hasClass('frame')) {
break;
}
frame = frame.parent();
}
if (!frame.hasClass('frame')) {
$element.remove();
return;
}
frame = frame[0];
var layoutContainer = frame.parentElement,
isOpen = false,
overlay,
closeButton,
blocker,
overlayContainer;
function openOverlay() {
// Remove frame classes from being applied in a non-frame context
$(frame).removeClass('frame frame-template');
overlayContainer = overlay.querySelector('.abs.contents');
closeButton = overlay.querySelector('a.close');
closeButton.addEventListener('click', toggleOverlay);
blocker = overlay.querySelector('.abs.blocker');
blocker.addEventListener('click', toggleOverlay);
document.body.appendChild(overlay);
layoutContainer.removeChild(frame);
overlayContainer.appendChild(frame);
}
function closeOverlay() {
$(frame).addClass('frame frame-template');
overlayContainer.removeChild(frame);
layoutContainer.appendChild(frame);
document.body.removeChild(overlay);
closeButton.removeEventListener('click', toggleOverlay);
closeButton = undefined;
blocker.removeEventListener('click', toggleOverlay);
blocker = undefined;
overlayContainer = undefined;
overlay = undefined;
}
function initOpenOverlay() {
overlay = document.createElement('span');
overlay.innerHTML = OVERLAY_TEMPLATE;
// Give expand anim time to run before populating
setTimeout(openOverlay(), 5000);
}
function toggleOverlay() {
if (!isOpen) {
initOpenOverlay();
isOpen = true;
} else {
closeOverlay();
isOpen = false;
}
}
$element.on('click', toggleOverlay);
$scope.$on('$destroy', function () {
$element.off('click');
});
}
return {
restrict: 'A',
link: link
};
}
return MCTTriggerModal;
});

View File

@@ -1,37 +0,0 @@
# Plot README
## Chart
The `mct-chart` directive is used to support drawing of simple charts. It is
present to support the Plot view, and its functionality is limited to the
functionality that is relevant for that view.
This directive is used at the element level and takes one attribute, `draw`
which is an Angular expression which will should evaluate to a drawing object.
This drawing object should contain the following properties:
* `dimensions`: The size, in logical coordinates, of the chart area. A
two-element array or numbers.
* `origin`: The position, in logical coordinates, of the lower-left corner of
the chart area. A two-element array or numbers.
* `lines`: An array of lines (e.g. as a plot line) to draw, where each line is
expressed as an object containing:
* `buffer`: A Float32Array containing points in the line, in logical
coordinates, in sequential x,y pairs.
* `color`: The color of the line, as a four-element RGBA array, where
each element is a number in the range of 0.0-1.0.
* `points`: The number of points in the line.
* `boxes`: An array of rectangles to draw in the chart area. Each is an object
containing:
* `start`: The first corner of the rectangle, as a two-element array of
numbers, in logical coordinates.
* `end`: The opposite corner of the rectangle, as a two-element array of
numbers, in logical coordinates. color : The color of the line, as a
four-element RGBA array, where each element is a number in the range of
0.0-1.0.
While `mct-chart` is intended to support plots specifically, it does perform
some useful management of canvas objects (e.g. choosing between WebGL and Canvas
2D APIs for drawing based on browser support) so its usage is recommended when
its supported drawing primitives are sufficient for other charting tasks.

View File

@@ -38,7 +38,6 @@ define([
"./src/directives/MCTSwimlaneDrop",
"./src/directives/MCTSwimlaneDrag",
"./src/services/ObjectLoader",
"./src/chart/MCTTimelineChart",
"text!./res/templates/values.html",
"text!./res/templates/timeline.html",
"text!./res/templates/activity-gantt.html",
@@ -68,7 +67,6 @@ define([
MCTSwimlaneDrop,
MCTSwimlaneDrag,
ObjectLoader,
MCTTimelineChart,
valuesTemplate,
timelineTemplate,
activityGanttTemplate,
@@ -558,14 +556,6 @@ define([
"depends": [
"dndService"
]
},
{
"key": "mctTimelineChart",
"implementation": MCTTimelineChart,
"depends": [
"$interval",
"$log"
]
}
],
"services": [

View File

@@ -22,7 +22,7 @@
<span ng-controller="TimelineGraphController as graphController">
<div class="t-graph l-graph" ng-repeat="graph in parameters.graphs">
<div class="l-graph-area l-canvas-holder">
<mct-timeline-chart draw="graph.drawingObject"></mct-timeline-chart>
<mct-chart draw="graph.drawingObject"></mct-chart>
</div>
<div class="t-graph-labels l-graph-labels">
<mct-include key="'timeline-resource-graph-labels'"
@@ -31,4 +31,4 @@
</mct-include>
</div>
</div>
</span>
</span>

View File

@@ -1,117 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Create a new chart which uses Canvas's 2D API for rendering.
*
* @memberof platform/features/plot
* @constructor
* @implements {platform/features/plot.Chart}
* @param {CanvasElement} canvas the canvas object to render upon
* @throws {Error} an error is thrown if Canvas's 2D API is unavailable.
*/
function Canvas2DChart(canvas) {
this.canvas = canvas;
this.c2d = canvas.getContext('2d');
this.width = canvas.width;
this.height = canvas.height;
this.dimensions = [this.width, this.height];
this.origin = [0, 0];
if (!this.c2d) {
throw new Error("Canvas 2d API unavailable.");
}
}
// Convert from logical to physical x coordinates
Canvas2DChart.prototype.x = function (v) {
return ((v - this.origin[0]) / this.dimensions[0]) * this.width;
};
// Convert from logical to physical y coordinates
Canvas2DChart.prototype.y = function (v) {
return this.height -
((v - this.origin[1]) / this.dimensions[1]) * this.height;
};
// Set the color to be used for drawing operations
Canvas2DChart.prototype.setColor = function (color) {
var mappedColor = color.map(function (c, i) {
return i < 3 ? Math.floor(c * 255) : (c);
}).join(',');
this.c2d.strokeStyle = "rgba(" + mappedColor + ")";
this.c2d.fillStyle = "rgba(" + mappedColor + ")";
};
Canvas2DChart.prototype.clear = function () {
var canvas = this.canvas;
this.width = canvas.width;
this.height = canvas.height;
this.c2d.clearRect(0, 0, this.width, this.height);
};
Canvas2DChart.prototype.setDimensions = function (newDimensions, newOrigin) {
this.dimensions = newDimensions;
this.origin = newOrigin;
};
Canvas2DChart.prototype.drawLine = function (buf, color, points) {
var i;
this.setColor(color);
// Configure context to draw two-pixel-thick lines
this.c2d.lineWidth = 2;
// Start a new path...
if (buf.length > 1) {
this.c2d.beginPath();
this.c2d.moveTo(this.x(buf[0]), this.y(buf[1]));
}
// ...and add points to it...
for (i = 2; i < points * 2; i = i + 2) {
this.c2d.lineTo(this.x(buf[i]), this.y(buf[i + 1]));
}
// ...before finally drawing it.
this.c2d.stroke();
};
Canvas2DChart.prototype.drawSquare = function (min, max, color) {
var x1 = this.x(min[0]),
y1 = this.y(min[1]),
w = this.x(max[0]) - x1,
h = this.y(max[1]) - y1;
this.setColor(color);
this.c2d.fillRect(x1, y1, w, h);
};
return Canvas2DChart;
}
);

View File

@@ -1,160 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Module defining GLPlot. Created by vwoeltje on 11/12/14.
*/
define(
[],
function () {
// WebGL shader sources (for drawing plain colors)
var FRAGMENT_SHADER = [
"precision mediump float;",
"uniform vec4 uColor;",
"void main(void) {",
"gl_FragColor = uColor;",
"}"
].join('\n'),
VERTEX_SHADER = [
"attribute vec2 aVertexPosition;",
"uniform vec2 uDimensions;",
"uniform vec2 uOrigin;",
"void main(void) {",
"gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);",
"}"
].join('\n');
/**
* Create a new chart which uses WebGL for rendering.
*
* @memberof platform/features/plot
* @constructor
* @implements {platform/features/plot.Chart}
* @param {CanvasElement} canvas the canvas object to render upon
* @throws {Error} an error is thrown if WebGL is unavailable.
*/
function GLChart(canvas) {
var gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }) ||
canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true }),
vertexShader,
fragmentShader,
program,
aVertexPosition,
uColor,
uDimensions,
uOrigin;
// Ensure a context was actually available before proceeding
if (!gl) {
throw new Error("WebGL unavailable.");
}
// Initialize shaders
vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, VERTEX_SHADER);
gl.compileShader(vertexShader);
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, FRAGMENT_SHADER);
gl.compileShader(fragmentShader);
// Assemble vertex/fragment shaders into programs
program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
// Get locations for attribs/uniforms from the
// shader programs (to pass values into shaders at draw-time)
aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
uColor = gl.getUniformLocation(program, "uColor");
uDimensions = gl.getUniformLocation(program, "uDimensions");
uOrigin = gl.getUniformLocation(program, "uOrigin");
gl.enableVertexAttribArray(aVertexPosition);
// Create a buffer to holds points which will be drawn
this.buffer = gl.createBuffer();
// Use a line width of 2.0 for legibility
gl.lineWidth(2.0);
// Enable blending, for smoothness
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
this.gl = gl;
this.aVertexPosition = aVertexPosition;
this.uColor = uColor;
this.uDimensions = uDimensions;
this.uOrigin = uOrigin;
}
// Utility function to handle drawing of a buffer;
// drawType will determine whether this is a box, line, etc.
GLChart.prototype.doDraw = function (drawType, buf, color, points) {
var gl = this.gl;
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.bufferData(gl.ARRAY_BUFFER, buf, gl.DYNAMIC_DRAW);
gl.vertexAttribPointer(this.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
gl.uniform4fv(this.uColor, color);
gl.drawArrays(drawType, 0, points);
};
GLChart.prototype.clear = function () {
var gl = this.gl;
// Set the viewport size; note that we use the width/height
// that our WebGL context reports, which may be lower
// resolution than the canvas we requested.
gl.viewport(
0,
0,
gl.drawingBufferWidth,
gl.drawingBufferHeight
);
gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT);
};
GLChart.prototype.setDimensions = function (dimensions, origin) {
var gl = this.gl;
if (dimensions && dimensions.length > 0 &&
origin && origin.length > 0) {
gl.uniform2fv(this.uDimensions, dimensions);
gl.uniform2fv(this.uOrigin, origin);
}
};
GLChart.prototype.drawLine = function (buf, color, points) {
this.doDraw(this.gl.LINE_STRIP, buf, color, points);
};
GLChart.prototype.drawSquare = function (min, max, color) {
this.doDraw(this.gl.TRIANGLE_FAN, new Float32Array(
min.concat([min[0], max[1]]).concat(max).concat([max[0], min[1]])
), color, 4);
};
return GLChart;
}
);

View File

@@ -1,250 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Module defining MCTTimelineChart. Created by vwoeltje on 11/12/14.
*/
define(
["./GLChart", "./Canvas2DChart"],
function (GLChart, Canvas2DChart) {
var TEMPLATE = "<canvas style='position: absolute; background: none; width: 100%; height: 100%;'></canvas>";
/**
* The mct-timeline-chart directive provides a canvas element which can be
* drawn upon, to support Plot view and similar visualizations.
*
* This directive takes one attribute, "draw", which is an Angular
* expression which will be two-way bound to a drawing object. This
* drawing object should contain:
*
* * `dimensions`: An object describing the logical bounds of the
* drawable area, containing two fields:
* * `origin`: The position, in logical coordinates, of the
* lower-left corner of the chart area. A two-element array.
* * `dimensions`: A two-element array containing the width
* and height of the chart area, in logical coordinates.
* * `lines`: An array of lines to be drawn, where each line is
* expressed as an object containing:
* * `buffer`: A Float32Array containing points in the line,
* in logical coordinate, in sequential x/y pairs.
* * `color`: The color of the line, as a four-element RGBA
* array, where each element is in the range of 0.0-1.0
* * `points`: The number of points in the line.
* * `boxes`: An array of rectangles to draw in the chart area
* (used for marquee zoom). Each is an object containing:
* * `start`: The first corner of the rectangle (as a two-element
* array, logical coordinates)
* * `end`: The opposite corner of the rectangle (again, as a
* two-element array)
* * `color`: The color of the box, as a four-element RGBA
* array, where each element is in the range of 0.0-1.0
*
* @memberof platform/features/plot
* @constructor
*/
function MCTTimelineChart($interval, $log) {
// Get an underlying chart implementation
function getChart(Charts, canvas) {
// Try the first available option...
var Chart = Charts[0];
// This function recursively try-catches all options;
// if these all fail, issue a warning.
if (!Chart) {
$log.warn("Cannot initialize mct-timeline-chart.");
return undefined;
}
// Try first option; if it fails, try remaining options
try {
return new Chart(canvas);
} catch (e) {
$log.warn([
"Could not instantiate chart",
Chart.name,
";",
e.message
].join(" "));
return getChart(Charts.slice(1), canvas);
}
}
function linkChart(scope, element) {
var canvas = element.find("canvas")[0],
activeInterval,
chart;
// Handle drawing, based on contents of the "draw" object
// in scope
function doDraw(draw) {
// Ensure canvas context has same resolution
// as canvas element
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
// Clear previous contents
chart.clear();
// Nothing to draw if no draw object defined
if (!draw) {
return;
}
// Set logical boundaries for the chart
chart.setDimensions(
draw.dimensions || [1, 1],
draw.origin || [0, 0]
);
// Draw line segments
(draw.lines || []).forEach(function (line) {
chart.drawLine(
line.buffer,
line.color,
line.points
);
});
// Draw boxes (e.g. marquee zoom rect)
(draw.boxes || []).forEach(function (box) {
chart.drawSquare(
box.start,
box.end,
box.color
);
});
}
// Issue a drawing call, if-and-only-if canvas size
// has changed. This will be called on a timer, since
// there is no event to depend on.
function drawIfResized() {
if (canvas.width !== canvas.offsetWidth ||
canvas.height !== canvas.offsetHeight) {
doDraw(scope.draw);
scope.$apply();
}
}
// Stop watching for changes to size (scope destroyed)
function releaseInterval() {
if (activeInterval) {
$interval.cancel(activeInterval);
}
}
// Switch from WebGL to plain 2D if context is lost
function fallbackFromWebGL() {
element.html(TEMPLATE);
canvas = element.find("canvas")[0];
chart = getChart([Canvas2DChart], canvas);
if (chart) {
doDraw(scope.draw);
}
}
// Try to initialize a chart.
chart = getChart([GLChart, Canvas2DChart], canvas);
// If that failed, there's nothing more we can do here.
// (A warning will already have been issued)
if (!chart) {
return;
}
// WebGL is a bit of a special case; it may work, then fail
// later for various reasons, so we need to listen for this
// and fall back to plain canvas drawing when it occurs.
canvas.addEventListener("webglcontextlost", fallbackFromWebGL);
// Check for resize, on a timer
activeInterval = $interval(drawIfResized, 1000, 0, false);
// Watch "draw" for external changes to the set of
// things to be drawn.
scope.$watchCollection("draw", doDraw);
// Stop checking for resize when scope is destroyed
scope.$on("$destroy", releaseInterval);
}
return {
// Apply directive only to elements
restrict: "E",
// Template to use (a canvas element)
template: TEMPLATE,
// Link function; set up scope
link: linkChart,
// Initial, isolate scope for the directive
scope: { draw: "=" }
};
}
/**
* @interface platform/features/plot.Chart
* @private
*/
/**
* Clear the chart.
* @method platform/features/plot.Chart#clear
*/
/**
* Set the logical boundaries of the chart.
* @param {number[]} dimensions the horizontal and
* vertical dimensions of the chart
* @param {number[]} origin the horizontal/vertical
* origin of the chart
* @memberof platform/features/plot.Chart#setDimensions
*/
/**
* Draw the supplied buffer as a line strip (a sequence
* of line segments), in the chosen color.
* @param {Float32Array} buf the line strip to draw,
* in alternating x/y positions
* @param {number[]} color the color to use when drawing
* the line, as an RGBA color where each element
* is in the range of 0.0-1.0
* @param {number} points the number of points to draw
* @memberof platform/features/plot.Chart#drawLine
*/
/**
* Draw a rectangle extending from one corner to another,
* in the chosen color.
* @param {number[]} min the first corner of the rectangle
* @param {number[]} max the opposite corner
* @param {number[]} color the color to use when drawing
* the rectangle, as an RGBA color where each element
* is in the range of 0.0-1.0
* @memberof platform/features/plot.Chart#drawSquare
*/
return MCTTimelineChart;
}
);

View File

@@ -167,7 +167,7 @@ define(
*/
setBounds: function (offset, duration) {
// We don't update in-place, because we need the change
// to trigger a watch in mct-timeline-chart.
// to trigger a watch in mct-chart.
drawingObject.origin = [offset, drawingObject.origin[1]];
drawingObject.dimensions = [duration, drawingObject.dimensions[1]];
},

View File

@@ -26,7 +26,7 @@ define(
/**
* Responsible for preparing data for display by
* `mct-timeline-chart` in a timeline's resource graph.
* `mct-chart` in a timeline's resource graph.
* @constructor
*/
function TimelineGraphRenderer() {
@@ -54,7 +54,7 @@ define(
* Convert an HTML color (in #-prefixed 6-digit hexadecimal)
* to an array of floating point values in a range of 0.0-1.0.
* An alpha element is included to facilitate display in an
* `mct-timeline-chart` (which uses WebGL.)
* `mct-chart` (which uses WebGL.)
* @param {string} the color
* @returns {number[]} the same color, in floating-point format
*/

View File

@@ -1,95 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* MergeModelsSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/chart/Canvas2DChart"],
function (Canvas2DChart) {
describe("A canvas 2d chart", function () {
var mockCanvas,
mock2d,
chart;
beforeEach(function () {
mockCanvas = jasmine.createSpyObj("canvas", ["getContext"]);
mock2d = jasmine.createSpyObj(
"2d",
[
"clearRect",
"beginPath",
"moveTo",
"lineTo",
"stroke",
"fillRect"
]
);
mockCanvas.getContext.andReturn(mock2d);
chart = new Canvas2DChart(mockCanvas);
});
// Note that tests below are less specific than they
// could be, esp. w.r.t. arguments to drawing calls;
// this is a fallback option so is a lower test priority.
it("allows the canvas to be cleared", function () {
chart.clear();
expect(mock2d.clearRect).toHaveBeenCalled();
});
it("does not construct if 2D is unavailable", function () {
mockCanvas.getContext.andReturn(undefined);
expect(function () {
return new Canvas2DChart(mockCanvas);
}).toThrow();
});
it("allows dimensions to be set", function () {
// No return value, just verify API is present
chart.setDimensions([120, 120], [0, 10]);
});
it("allows lines to be drawn", function () {
var testBuffer = [0, 1, 3, 8],
testColor = [0.25, 0.33, 0.66, 1.0],
testPoints = 2;
chart.drawLine(testBuffer, testColor, testPoints);
expect(mock2d.beginPath).toHaveBeenCalled();
expect(mock2d.lineTo.calls.length).toEqual(1);
expect(mock2d.stroke).toHaveBeenCalled();
});
it("allows squares to be drawn", function () {
var testMin = [0, 1],
testMax = [10, 10],
testColor = [0.25, 0.33, 0.66, 1.0];
chart.drawSquare(testMin, testMax, testColor);
expect(mock2d.fillRect).toHaveBeenCalled();
});
});
}
);

View File

@@ -1,143 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* MergeModelsSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/chart/GLChart"],
function (GLChart) {
describe("A WebGL chart", function () {
var mockCanvas,
mockGL,
glChart;
beforeEach(function () {
mockCanvas = jasmine.createSpyObj("canvas", ["getContext"]);
mockGL = jasmine.createSpyObj(
"gl",
[
"createShader",
"compileShader",
"shaderSource",
"attachShader",
"createProgram",
"linkProgram",
"useProgram",
"enableVertexAttribArray",
"getAttribLocation",
"getUniformLocation",
"createBuffer",
"lineWidth",
"enable",
"blendFunc",
"viewport",
"clear",
"uniform2fv",
"uniform4fv",
"bufferData",
"bindBuffer",
"vertexAttribPointer",
"drawArrays"
]
);
mockGL.ARRAY_BUFFER = "ARRAY_BUFFER";
mockGL.DYNAMIC_DRAW = "DYNAMIC_DRAW";
mockGL.TRIANGLE_FAN = "TRIANGLE_FAN";
mockGL.LINE_STRIP = "LINE_STRIP";
// Echo back names for uniform locations, so we can
// test which of these are set for certain operations.
mockGL.getUniformLocation.andCallFake(function (a, name) {
return name;
});
mockCanvas.getContext.andReturn(mockGL);
glChart = new GLChart(mockCanvas);
});
it("allows the canvas to be cleared", function () {
glChart.clear();
expect(mockGL.clear).toHaveBeenCalled();
});
it("does not construct if WebGL is unavailable", function () {
mockCanvas.getContext.andReturn(undefined);
expect(function () {
return new GLChart(mockCanvas);
}).toThrow();
});
it("allows dimensions to be set", function () {
glChart.setDimensions([120, 120], [0, 10]);
expect(mockGL.uniform2fv)
.toHaveBeenCalledWith("uDimensions", [120, 120]);
expect(mockGL.uniform2fv)
.toHaveBeenCalledWith("uOrigin", [0, 10]);
});
it("allows lines to be drawn", function () {
var testBuffer = [0, 1, 3, 8],
testColor = [0.25, 0.33, 0.66, 1.0],
testPoints = 2;
glChart.drawLine(testBuffer, testColor, testPoints);
expect(mockGL.bufferData).toHaveBeenCalledWith(
mockGL.ARRAY_BUFFER,
testBuffer,
mockGL.DYNAMIC_DRAW
);
expect(mockGL.uniform4fv)
.toHaveBeenCalledWith("uColor", testColor);
expect(mockGL.drawArrays)
.toHaveBeenCalledWith("LINE_STRIP", 0, testPoints);
});
it("allows squares to be drawn", function () {
var testMin = [0, 1],
testMax = [10, 10],
testColor = [0.25, 0.33, 0.66, 1.0];
glChart.drawSquare(testMin, testMax, testColor);
expect(mockGL.uniform4fv)
.toHaveBeenCalledWith("uColor", testColor);
expect(mockGL.drawArrays)
.toHaveBeenCalledWith("TRIANGLE_FAN", 0, 4);
});
it("uses buffer sizes reported by WebGL", function () {
// Make sure that GLChart uses the GL buffer size, which may
// differ from what canvas requested. WTD-852
mockCanvas.width = 300;
mockCanvas.height = 150;
mockGL.drawingBufferWidth = 200;
mockGL.drawingBufferHeight = 175;
glChart.clear();
expect(mockGL.viewport).toHaveBeenCalledWith(0, 0, 200, 175);
});
});
}
);

View File

@@ -1,216 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* MCTTimelineChart. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/chart/MCTTimelineChart"],
function (MCTTimelineChart) {
describe("The mct-timeline-chart directive", function () {
var mockInterval,
mockLog,
mockScope,
mockElement,
mockCanvas,
mockGL,
mockC2d,
mockPromise,
mctChart;
beforeEach(function () {
mockInterval =
jasmine.createSpy("$interval");
mockLog =
jasmine.createSpyObj("$log", ["warn", "info", "debug"]);
mockScope = jasmine.createSpyObj(
"$scope",
["$watchCollection", "$on", "$apply"]
);
mockElement =
jasmine.createSpyObj("element", ["find", "html"]);
mockInterval.cancel = jasmine.createSpy("cancelInterval");
mockPromise = jasmine.createSpyObj("promise", ["then"]);
// mct-timeline-chart uses GLChart, so it needs WebGL API
mockCanvas =
jasmine.createSpyObj("canvas", ["getContext", "addEventListener"]);
mockGL = jasmine.createSpyObj(
"gl",
[
"createShader",
"compileShader",
"shaderSource",
"attachShader",
"createProgram",
"linkProgram",
"useProgram",
"enableVertexAttribArray",
"getAttribLocation",
"getUniformLocation",
"createBuffer",
"lineWidth",
"enable",
"blendFunc",
"viewport",
"clear",
"uniform2fv",
"uniform4fv",
"bufferData",
"bindBuffer",
"vertexAttribPointer",
"drawArrays"
]
);
mockC2d = jasmine.createSpyObj('c2d', ['clearRect']);
mockGL.ARRAY_BUFFER = "ARRAY_BUFFER";
mockGL.DYNAMIC_DRAW = "DYNAMIC_DRAW";
mockGL.TRIANGLE_FAN = "TRIANGLE_FAN";
mockGL.LINE_STRIP = "LINE_STRIP";
// Echo back names for uniform locations, so we can
// test which of these are set for certain operations.
mockGL.getUniformLocation.andCallFake(function (a, name) {
return name;
});
mockElement.find.andReturn([mockCanvas]);
mockCanvas.getContext.andCallFake(function (type) {
return { webgl: mockGL, '2d': mockC2d }[type];
});
mockInterval.andReturn(mockPromise);
mctChart = new MCTTimelineChart(mockInterval, mockLog);
});
it("is applicable at the element level", function () {
expect(mctChart.restrict).toEqual("E");
});
it("places a 'draw' attribute in-scope", function () {
// Should ask Angular for the draw attribute
expect(mctChart.scope.draw).toEqual("=");
});
it("watches for changes in the drawn object", function () {
mctChart.link(mockScope, mockElement);
expect(mockScope.$watchCollection)
.toHaveBeenCalledWith("draw", jasmine.any(Function));
});
it("issues one draw call per line", function () {
mctChart.link(mockScope, mockElement);
mockScope.$watchCollection.mostRecentCall.args[1]({
lines: [{}, {}, {}]
});
expect(mockGL.drawArrays.calls.length).toEqual(3);
});
it("issues one draw call per box", function () {
mctChart.link(mockScope, mockElement);
mockScope.$watchCollection.mostRecentCall.args[1]({
boxes: [
{ start: [0, 0], end: [1, 1] },
{ start: [0, 0], end: [1, 1] },
{ start: [0, 0], end: [1, 1] },
{ start: [0, 0], end: [1, 1] }
]
});
expect(mockGL.drawArrays.calls.length).toEqual(4);
});
it("does not fail if no draw object is in scope", function () {
mctChart.link(mockScope, mockElement);
expect(mockScope.$watchCollection.mostRecentCall.args[1])
.not.toThrow();
});
it("draws on canvas resize", function () {
mctChart.link(mockScope, mockElement);
// Should track canvas size in an interval
expect(mockInterval).toHaveBeenCalledWith(
jasmine.any(Function),
jasmine.any(Number),
0,
false
);
// Verify pre-condition
expect(mockGL.clear).not.toHaveBeenCalled();
mockCanvas.width = 100;
mockCanvas.offsetWidth = 150;
mockCanvas.height = 200;
mockCanvas.offsetHeight = 200;
mockInterval.mostRecentCall.args[0]();
// Use clear as an indication that drawing has occurred
expect(mockGL.clear).toHaveBeenCalled();
});
it("warns if no WebGL context is available", function () {
mockCanvas.getContext.andReturn(undefined);
mctChart.link(mockScope, mockElement);
expect(mockLog.warn).toHaveBeenCalled();
});
it("falls back to Canvas 2d API if WebGL context is lost", function () {
mctChart.link(mockScope, mockElement);
expect(mockCanvas.addEventListener)
.toHaveBeenCalledWith("webglcontextlost", jasmine.any(Function));
expect(mockCanvas.getContext).not.toHaveBeenCalledWith('2d');
mockCanvas.addEventListener.mostRecentCall.args[1]();
expect(mockCanvas.getContext).toHaveBeenCalledWith('2d');
});
it("logs nothing in nominal situations (WebGL available)", function () {
// Complement the previous test
mctChart.link(mockScope, mockElement);
expect(mockLog.warn).not.toHaveBeenCalled();
});
// Avoid resource leaks
it("stops polling for size changes on destroy", function () {
mctChart.link(mockScope, mockElement);
// Should be listening for a destroy event
expect(mockScope.$on).toHaveBeenCalledWith(
"$destroy",
jasmine.any(Function)
);
// Precondition - interval still active
expect(mockInterval.cancel).not.toHaveBeenCalled();
// Broadcast a $destroy
mockScope.$on.mostRecentCall.args[1]();
// Should have stopped the interval
expect(mockInterval.cancel).toHaveBeenCalledWith(mockPromise);
});
});
}
);

View File

@@ -122,12 +122,9 @@ define(
*/
self.getDatum = function (telemetryObject, index) {
function makeNewDatum(series) {
if (series) {
if (series.getDatum) {
return series.getDatum(index);
}
return subscription.makeDatum(telemetryObject, series, index);
}
return series ?
subscription.makeDatum(telemetryObject, series, index) :
undefined;
}
return typeof index !== 'number' ?

View File

@@ -21,12 +21,13 @@
*****************************************************************************/
define([
'./object-utils'
'./object-utils',
'./objectEventEmitter'
], function (
utils
utils,
objectEventEmitter
) {
function ObjectServiceProvider(eventEmitter, objectService, instantiate, topic) {
this.eventEmitter = eventEmitter;
function ObjectServiceProvider(objectService, instantiate, topic) {
this.objectService = objectService;
this.instantiate = instantiate;
@@ -60,12 +61,12 @@ define([
var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId());
//Don't trigger self
this.eventEmitter.off('mutation', handleMutation);
this.eventEmitter.emit(newStyleObject.identifier.key + ":*", newStyleObject);
this.eventEmitter.on('mutation', handleMutation);
objectEventEmitter.off('mutation', handleMutation);
objectEventEmitter.emit(newStyleObject.identifier.key + ":*", newStyleObject);
objectEventEmitter.on('mutation', handleMutation);
}.bind(this);
this.eventEmitter.on('mutation', handleMutation);
objectEventEmitter.on('mutation', handleMutation);
removeGeneralTopicListener = this.generalTopic.listen(handleLegacyMutation);
};
@@ -95,8 +96,6 @@ define([
// Injects new object API as a decorator so that it hijacks all requests.
// Object providers implemented on new API should just work, old API should just work, many things may break.
function LegacyObjectAPIInterceptor(openmct, ROOTS, instantiate, topic, objectService) {
var eventEmitter = openmct.objects.eventEmitter;
this.getObjects = function (keys) {
var results = {},
promises = keys.map(function (keyString) {
@@ -115,12 +114,7 @@ define([
};
openmct.objects.supersecretSetFallbackProvider(
new ObjectServiceProvider(
eventEmitter,
objectService,
instantiate,
topic
)
new ObjectServiceProvider(objectService, instantiate, topic)
);
ROOTS.forEach(function (r) {

View File

@@ -21,9 +21,11 @@
*****************************************************************************/
define([
'lodash'
'lodash',
'./objectEventEmitter'
], function (
_
_,
objectEventEmitter
) {
var ANY_OBJECT_EVENT = "mutation";
@@ -34,8 +36,7 @@ define([
* @param object
* @interface MutableObject
*/
function MutableObject(eventEmitter, object) {
this.eventEmitter = eventEmitter;
function MutableObject(object) {
this.object = object;
this.unlisteners = [];
}
@@ -60,11 +61,8 @@ define([
*/
MutableObject.prototype.on = function (path, callback) {
var fullPath = qualifiedEventName(this.object, path);
var eventOff =
this.eventEmitter.off.bind(this.eventEmitter, fullPath, callback);
this.eventEmitter.on(fullPath, callback);
this.unlisteners.push(eventOff);
objectEventEmitter.on(fullPath, callback);
this.unlisteners.push(objectEventEmitter.off.bind(objectEventEmitter, fullPath, callback));
};
/**
@@ -80,12 +78,12 @@ define([
_.set(this.object, 'modified', Date.now());
//Emit event specific to property
this.eventEmitter.emit(qualifiedEventName(this.object, path), value);
objectEventEmitter.emit(qualifiedEventName(this.object, path), value);
//Emit wildcare event
this.eventEmitter.emit(qualifiedEventName(this.object, '*'), this.object);
objectEventEmitter.emit(qualifiedEventName(this.object, '*'), this.object);
//Emit a general "any object" event
this.eventEmitter.emit(ANY_OBJECT_EVENT, this.object);
objectEventEmitter.emit(ANY_OBJECT_EVENT, this.object);
};
return MutableObject;

View File

@@ -25,15 +25,13 @@ define([
'./object-utils',
'./MutableObject',
'./RootRegistry',
'./RootObjectProvider',
'EventEmitter'
'./RootObjectProvider'
], function (
_,
utils,
MutableObject,
RootRegistry,
RootObjectProvider,
EventEmitter
RootObjectProvider
) {
@@ -44,7 +42,6 @@ define([
*/
function ObjectAPI() {
this.eventEmitter = new EventEmitter();
this.providers = {};
this.rootRegistry = new RootRegistry();
this.rootProvider = new RootObjectProvider(this.rootRegistry);
@@ -178,9 +175,7 @@ define([
* @memberof module:openmct.ObjectAPI#
*/
ObjectAPI.prototype.mutate = function (domainObject, path, value) {
var mutableObject =
new MutableObject(this.eventEmitter, domainObject);
return mutableObject.set(path, value);
return new MutableObject(domainObject).set(path, value);
};
/**
@@ -193,8 +188,7 @@ define([
* @memberof module:openmct.ObjectAPI#
*/
ObjectAPI.prototype.observe = function (domainObject, path, callback) {
var mutableObject =
new MutableObject(this.eventEmitter, domainObject);
var mutableObject = new MutableObject(domainObject);
mutableObject.on(path, callback);
return mutableObject.stopListening.bind(mutableObject);
};

View File

@@ -45,9 +45,6 @@ define([
};
function createDatum(domainObject, metadata, legacySeries, i) {
if (legacySeries.getDatum) {
return legacySeries.getDatum(i);
}
var datum = {};
metadata.domains.reduce(function (d, domain) {

View File

@@ -109,6 +109,7 @@ define([
'platform/commonUI/general',
'platform/commonUI/inspect',
'platform/commonUI/mobile',
'platform/commonUI/themes/espresso',
'platform/commonUI/notification',
'platform/containment',
'platform/execution',

View File

@@ -21,67 +21,13 @@
*****************************************************************************/
define([
'lodash'
], function (_) {
var bundleMap = {
couchDB: 'platform/persistence/couch',
elasticsearch: 'platform/persistence/elastic',
espresso: 'platform/commonUI/themes/espresso',
localStorage: 'platform/persistence/local',
myItems: 'platform/features/my-items',
snow: 'platform/commonUI/themes/snow',
utcTimeSystem: 'platform/features/conductor/utcTimeSystem'
], function () {
return {
localStorage: function (openmct) {
openmct.legacyRegistry.enable('platform/persistence/local');
},
myItems: function (openmct) {
openmct.legacyRegistry.enable('platform/features/my-items');
}
};
var plugins = _.mapValues(bundleMap, function (bundleName, pluginName) {
return function (openmct) {
openmct.legacyRegistry.enable(bundleName);
};
});
plugins.CouchDB = function (url) {
return function (openmct) {
if (url) {
var bundleName = "config/couch";
openmct.legacyRegistry.register(bundleName, {
"extensions": {
"constants": [
{
"key": "COUCHDB_PATH",
"value": url,
"priority": "mandatory"
}
]
}
});
openmct.legacyRegistry.enable(bundleName);
}
openmct.legacyRegistry.enable(bundleMap.couchDB);
};
};
plugins.Elasticsearch = function (url) {
return function (openmct) {
if (url) {
var bundleName = "config/elastic";
openmct.legacyRegistry.register(bundleName, {
"extensions": {
"constants": [
{
"key": "ELASTIC_ROOT",
"value": url,
"priority": "mandatory"
}
]
}
});
openmct.legacyRegistry.enable(bundleName);
}
openmct.legacyRegistry.enable(bundleMap.elasticsearch);
};
};
return plugins;
});