Compare commits

...

74 Commits

Author SHA1 Message Date
Pete Richards
3b86e02ed3 change proposed to actual 2016-10-26 12:10:22 -07:00
Victor Woeltjen
b4dc50295c Merge pull request #1131 from nasa/open1094
Resolve synchronization issues with MutableObject
2016-08-25 13:26:50 -07:00
Victor Woeltjen
382dde300a Merge remote-tracking branch 'origin/api-tutorials' into open1094
Conflicts:
	index.html
	tutorials/todo/todo.js
2016-08-25 13:25:54 -07:00
Victor Woeltjen
02aa08a3ef Merge pull request #1121 from nasa/api-containment
[API] Containment
2016-08-25 13:19:14 -07:00
Victor Woeltjen
c95d9c7956 Merge pull request #1107 from nasa/api-type-forms
[API] Handle forms with a "properties" region
2016-08-25 13:17:26 -07:00
Andrew Henry
b1b8df4d87 Use MutationCapability 2016-08-23 13:57:12 +01:00
Andrew Henry
bd3c6665fb Added bridge between old and new event models 2016-08-22 16:14:01 +01:00
Pete Richards
10e90519c0 Tidy todo views, remove unnecessary code 2016-08-22 16:10:45 +01:00
Pete Richards
d341a8be97 Selection changes include new selection 2016-08-22 16:10:45 +01:00
Andrew Henry
8c439d8109 Adding compatibility between old and new style mutation events 2016-08-22 07:59:17 +01:00
Henry
9c88b7ce1d Removed setters from MutableObject and fixed non-working todo list tutorial
Refactoring MutableObject

Fixed non-working todo example
2016-08-19 13:39:23 -07:00
Victor Woeltjen
2463e4d59f [API] Update Dialog API usage 2016-08-12 12:54:39 -07:00
Victor Woeltjen
d73c505bea [API] Fix typo, add missing this 2016-08-12 11:17:00 -07:00
Victor Woeltjen
831ecc59d9 [API] Wire in canContain via policy 2016-08-12 10:24:59 -07:00
Victor Woeltjen
1de26d3c5d [API] Throw error on containment violation 2016-08-12 09:30:02 -07:00
Victor Woeltjen
11409ce509 [API] Add containment methods 2016-08-12 09:27:46 -07:00
Victor Woeltjen
93872ce074 [API] Expose Dialog as constructor
...and use it that way from todo plugin
2016-08-11 16:04:26 -07:00
Victor Woeltjen
8861644f2d [API] Adjust Dialog API
...to allow OK button to be enabled/disabled.
2016-08-11 16:02:04 -07:00
Victor Woeltjen
d4948f771b Merge branch 'api-todo-update' into api-type-forms 2016-08-11 15:31:11 -07:00
Victor Woeltjen
8295a0bed1 [API] Update todo tutorial
...to expect new domain object API (instead of explicitly
wrapping it.)
2016-08-11 15:29:46 -07:00
Victor Woeltjen
0656a298da [API] Remove test usage of properties region 2016-08-04 14:00:48 -07:00
Victor Woeltjen
fe2ce91d50 [API] Show a custom view in dialog 2016-07-28 16:16:23 -07:00
Victor Woeltjen
14f30b2489 [API] Restrict dialog overrides
...to those domain objects which have some view for the
properties region registered.
2016-07-28 16:05:02 -07:00
Victor Woeltjen
62d90a8114 [API] Show dialog via mct 2016-07-28 15:57:15 -07:00
Victor Woeltjen
87682607a5 [API] Rename dependency in adapter layer 2016-07-28 15:53:07 -07:00
Victor Woeltjen
7bf265b478 [API] Move mct service up 2016-07-28 15:52:52 -07:00
Victor Woeltjen
1d31fe8d02 [API] Override dialogService in actions
An ugly hack to allow dialogs to be shown for Save As
and Edit Properties, without requiring form generation.
This will permit views to be shown instead in certain
cases, https://github.com/nasa/openmct/pull/999#issuecomment-236045158
2016-07-28 15:48:30 -07:00
Victor Woeltjen
bfdbc71e40 [API] Define a properties region 2016-07-28 15:34:03 -07:00
Pete Richards
1147f3aa47 tutorials: support arbitrary hosting directory (#1097)
* Include all bundles in artifact

change bundle registry such that all bundles are immediately registered,
but must be specifically enabled.  A default registry class enables bundles
that make sense for demonstration purposes.

Added methods to the registry to allow enabling and disabling of bundles
without having to load additional files.

* support alternate asset/worker paths

Change the gulp glob for assets to copy over a more minimal
set of files-- only css, fonts, and images.  Results in a
smaller distributable archive.

Update stylesheet loader to use a constant for the assets path.

This can be customized at run time via MCT.setAssetPath() to
allow MCT to be hosted in various locations.

Update worker loader to support loading workers from blobs to
support packaging as standalone file.

* Load templates via requirejs

* [gulp] lazy-require where reasonable

Require things right before starting tasks to reduce gulp start up time.

* document setAssetPath
2016-07-25 14:38:44 -07:00
Victor Woeltjen
719f9f45e8 [API] Add documentation for selection state (#1096) 2016-07-22 14:09:31 -07:00
Victor Woeltjen
95ef70a24c [API] Use selection state from toolbar (#1070)
* [API] Allow selection

* [API] Keep in sync using model

* [API] Add selection as EventEmitter

* [API] Use selection from ToDo tutorial

* [API] Restore selection functionality
2016-07-22 13:56:45 -07:00
Pete Richards
d5aa998b4c [API] Draft Composition API (#1068)
* [Objects] util for equality checking

Add a method for checking object equality, useful for other services.

* [Composition] Draft Composition API

Draft composition API.  Composition collections provide an observable
for watching and mutating the composition of an object.

Composition providers implement the loading and modification of composition.

The default composition provider uses the composition attribute of
domain objects, while allowing other providers to implement their
own loading and mutation behavior.

* add todo about event listener bindings

* [Type] Add form property for defining form fields

* [tutorial] Add Composition tutorial

* provider doesn't have to implement events, load returns array of children

* use new composition in old api

* correct key name

* Override instantiate to provide model ids

Override instantiate in public API adapter to prevent making changes to
platform code.  Instantiate now passes the id of the domain object with the
model so that capabilities can convert to a new-style domain object and use
that to detect functionality.

* Implement mutation capability with decorator

Implementation mutation capability override with decorator to adapter code
outside of platform.  Capability override ensures that models are kept in
sync even though they are no longer shared objects.

* override composition cleanly

Override composition capability without making changes inside platform.

* cleanup after temporary collections

* remove unused try/catch
2016-07-22 13:53:03 -07:00
Pete Richards
7890fcae69 tutorial consistency . (#1079)
* [API] use new-style objects consistently

* rewrite todo tutorial in test-api.html

* [API] Add API doc, update object API

* [Tutorials] Rename tutorials, remove old

* Fix Links

* updates

* initial

* hope this works

* Object Utils always return new objects instead of mutating existing objects

* keep domain object model in-sync when listening

Keep the domain object model in sync with the latest version when
listening for mutation events.

* Remove old-style plugins

* Update views to use new API

* Tidy Code

* Update API Docs

* Add Plugin API and Example
2016-07-21 14:39:02 -07:00
Victor Woeltjen
18843cee48 [API] Change approach to applies-to checking (#1072)
* [API] Allow selection

* [API] Keep in sync using model

* [API] Add selection as EventEmitter

* [API] Use selection from ToDo tutorial

* [API] Add appliesTo-style method

* [API] Remove destroy method, simplify show

* [View] Return a no-op

* [API] Use new applies-to checking

* [API] Rename TodoView to TodoRenderer

* [API] Rewire views

* [API] Wire up so that things work

* [API] Begin adding container

...to attempt to give views something to listen to for destroy-like
events

* [API] Begin using regions...

* [API] Begin working through Region stuff

* [API] Revise Region API

...for similarity with Marionette,
https://github.com/nasa/openmct/pull/1072#issuecomment-230902986

* [API] Begin separating View, ViewDefinition

* [API] Finish separating View/ViewDefinition

* [API] Update MCTView

...to reflect updates to Region/View/ViewDefinition APIs

* [API] Simplify View API

...merging closely-related populate/show methods, and restoring
compatibility with todo tutorial

* [API] Wire in from todo tutorial plugin

* [API] Switch back to region constants

* [API] Update method signature, add JSDoc

* [API] Update variable name

* [API] Remove unnecessary separate regions file

* [API] Relocate Region; not external api

* [API] Revert changes to api.js

...as these ended up becoming entirely superficial
2016-07-20 13:46:03 -07:00
Andrew Henry
1879c122c7 Mutation API (#1074)
* [API] Allow selection

* [API] Keep in sync using model

* [API] Add selection as EventEmitter

* [API] Use selection from ToDo tutorial

* Object events prototype

* Added examples

* Transitional API

* Modified todo list code to work with new setters

* [API] Removed emitting of events on container when property changes value to remove ambiguity. Listeners must be listening to the same path used in the setter to catch changes
2016-07-07 14:30:45 -07:00
Pete Richards
d7ddb96c4e [API] UMD Packaging (#1078)
* [Bundle] load filter with requirejs

* [Build] Use almond, wrap in UMD

Use almond for built version of application and wrap in UMD so that
it supports requirejs, commonjs, and basic browser loading.

* [Main] Can choose where to load app

MCT.run allows you to specify a dom element to load application
within.  If element is not specified, will use body.

* [MCT] set class on injected div

Set class on injected div so extra markup is not required.

* [Build] Re-enable optimize

* Add minimal bootstrap example
2016-07-07 14:25:23 -07:00
Andrew Henry
b55668426d Merge pull request #1062 from nasa/tc-redux
[Time Conductor] V2 Public API
2016-07-01 10:22:16 -07:00
Henry
5b656faa9d Added tests 2016-07-01 10:22:44 -07:00
Pete Richards
8d2c489fa9 [TimeConductor] Set bounds on timeSystem Change
Always set bounds on timeSystem change as not having valid bounds would
put views in inconsistent states.
2016-07-01 10:22:44 -07:00
Henry
4366b0870d [Time Conductor] API redesign. Initial commit of V2 public API. Addresses #933 2016-07-01 10:22:44 -07:00
Victor Woeltjen
47a543beb7 Merge pull request #1067 from nasa/api-css
[API] Remove stylesheet from example
2016-07-01 10:17:36 -07:00
Victor Woeltjen
06f87c1472 Merge pull request #1029 from nasa/api-toolbar-add-only
[API Prototype] Add toolbar
2016-07-01 10:13:29 -07:00
Victor Woeltjen
c9c41cdcc8 Merge remote-tracking branch 'origin/api-tutorials' into api-toolbar-add-only
Conflicts:
	src/MCT.js
2016-07-01 10:10:33 -07:00
Victor Woeltjen
14a56ea17e Merge pull request #1028 from nasa/api-view
[API Prototype] Support imperative view registration
2016-07-01 10:09:29 -07:00
Victor Woeltjen
b2e7db71cc Merge remote-tracking branch 'origin/api-tutorials' into api-view
Conflicts:
	src/MCT.js
	src/api/api.js
2016-07-01 10:08:05 -07:00
Victor Woeltjen
d51e6bfd92 Merge pull request #1030 from nasa/api-tutorial/objects
Api tutorial/objects
2016-07-01 10:03:42 -07:00
Victor Woeltjen
370b515c23 [API] Synchronize view to model 2016-06-17 14:21:37 -07:00
Victor Woeltjen
4a50f325cb [API] Allow tasks to be added 2016-06-17 14:18:51 -07:00
Victor Woeltjen
dbe6a4efc1 [API] Title dialog 2016-06-17 14:05:00 -07:00
Victor Woeltjen
13920d8802 [API] Resolve/reject from dialog 2016-06-17 14:00:45 -07:00
Victor Woeltjen
b6a8c514aa [API] Show dialog from toolbar 2016-06-17 13:51:15 -07:00
Victor Woeltjen
e4a4704baa [API] Listen to add/remove buttons 2016-06-17 13:41:59 -07:00
Victor Woeltjen
be0029e59a [API] Get todo toolbar to look right 2016-06-17 13:38:54 -07:00
Victor Woeltjen
9cb273ef0a [API] Get registered toolbar to appear 2016-06-17 13:30:08 -07:00
Victor Woeltjen
eec9b1cf4c [API] Support distinct region registration 2016-06-17 13:10:24 -07:00
Victor Woeltjen
1f96e84542 [API] Override template to allow toolbar injection 2016-06-17 12:16:46 -07:00
Victor Woeltjen
c289a27305 [API] Begin adding toolbar 2016-06-17 11:43:49 -07:00
Victor Woeltjen
c944080790 [API] Remove stylesheet from example
No need to provide custom API for this.
2016-06-17 11:27:04 -07:00
Victor Woeltjen
96316de6e4 [API] Update view API 2016-06-17 11:16:08 -07:00
Victor Woeltjen
2240a87ddc [API] Move view off of type 2016-06-17 10:53:56 -07:00
Victor Woeltjen
d891affe48 [API] Move view off of type 2016-06-17 10:21:00 -07:00
Victor Woeltjen
21a618d1ce Merge branch 'api-type-proto' into api-view 2016-06-17 10:19:44 -07:00
Victor Woeltjen
580a4e52b5 Merge branch 'api-tutorials' into api-type-driven 2016-06-07 14:01:08 -07:00
Victor Woeltjen
4ca2f51d5e [API] Use subclass style 2016-05-27 17:08:25 -07:00
Victor Woeltjen
86ac80ddbd [API] Persist mutations 2016-05-27 16:56:08 -07:00
Victor Woeltjen
0525ba6b0b [API] Check/uncheck todos 2016-05-27 16:55:10 -07:00
Victor Woeltjen
a79e958ffc [API] Show tasks from todo 2016-05-27 16:46:06 -07:00
Victor Woeltjen
03cb0ccb57 [API] Get View to render 2016-05-27 16:36:55 -07:00
Victor Woeltjen
7205faa6bb [API] Add adapter bundle 2016-05-27 16:27:47 -07:00
Victor Woeltjen
136f2ae785 [API] Add MCTView directive as an adapter 2016-05-27 16:19:20 -07:00
Victor Woeltjen
a07e2fb8e5 [API] Implement View 2016-05-27 16:08:43 -07:00
Victor Woeltjen
55b531bdeb [API] Sketch in view instantiation 2016-05-27 15:49:16 -07:00
Victor Woeltjen
7ece5897e8 [API] Begin adding View 2016-05-27 15:31:54 -07:00
Victor Woeltjen
a29c7a6eab [API] Deangularize todo templates 2016-05-27 13:46:30 -07:00
72 changed files with 4727 additions and 535 deletions

285
API.md Normal file
View File

@@ -0,0 +1,285 @@
# Open MCT API
The Open MCT framework public api can be utilized by building the application
(`gulp install`) and then copying the file from `dist/main.js` to your
directory of choice.
Open MCT supports AMD, CommonJS, and loading via a script tag; it's easy to use
in your project. The [`openmct`]{@link module:openmct} module is exported
via AMD and CommonJS, and is also exposed as `openmct` in the global scope
if loaded via a script tag.
## Overview
Open MCT's goal is to allow you to browse, create, edit, and visualize all of
the domain knowledge you need on a daily basis.
To do this, the main building block provided by Open MCT is the _domain object_.
The temperature sensor on the starboard solar panel,
an overlay plot comparing the results of all temperature sensor,
the command dictionary for a spacecraft,
the individual commands in that dictionary, your "my documents" folder:
All of these things are domain objects.
Domain objects have Types, so a specific instrument temperature sensor is a
"Telemetry Point," and turning on a drill for a certain duration of time is
an "Activity". Types allow you to form an ontology of knowledge and provide
an abstraction for grouping, visualizing, and interpreting data.
And then we have Views. Views allow you to visualize domain objects. Views can
apply to specific domain objects; they may also apply to certain types of
domain objects, or they may apply to everything. Views are simply a method
of visualizing domain objects.
Regions allow you to specify what views are displayed for specific types of
domain objects in response to different user actions. For instance, you may
want to display a different view while editing, or you may want to update the
toolbar display when objects are selected. Regions allow you to map views to
specific user actions.
Domain objects can be mutated and persisted, developers can create custom
actions and apply them to domain objects, and many more things can be done.
For more information, read on!
## Running Open MCT
Once the [`openmct`](@link module:openmct) module has been loaded, you can
simply invoke [`start`]{@link module:openmct.MCT#start} to run Open MCT:
```
openmct.start();
```
Generally, however, you will want to configure Open MCT by adding plugins
before starting it. It is important to install plugins and configure Open MCT
_before_ calling [`start`]{@link module:openmct.MCT#start}; Open MCT is not
designed to be reconfigured once started.
## Configuring Open MCT
The [`openmct`]{@link module:openmct} module (more specifically, the
[`MCT`]{@link module:openmct.MCT} class, of which `openmct` is an instance)
exposes a variety of methods to allow the application to be configured,
extended, and customized before running.
Short examples follow; see the linked documentation for further details.
### Adding Domain Object Types
Custom types may be registered via
[`openmct.types`]{@link module:openmct.MCT#types}:
```
openmct.types.addType('my-type', new openmct.Type({
label: "My Type",
description: "This is a type that I added!"
});
```
### Adding Views
Custom views may be registered based on the region in the application
where they should appear:
* [`openmct.mainViews`]{@link module:openmct.MCT#mainViews} is a registry
of views of domain objects which should appear in the main viewing area.
* [`openmct.inspectors`]{@link module:openmct.MCT#inspectors} is a registry
of views of domain objects and/or active selections, which should appear in
the Inspector.
* [`openmct.toolbars`]{@link module:openmct.MCT#toolbars} is a registry
of views of domain objects and/or active selections, which should appear in
the toolbar area while editing.
* [`openmct.indicators`]{@link module:openmct.MCT#inspectors} is a registry
of views which should appear in the status area of the application.
Example:
```
openmct.mainViews.addProvider({
canView: function (domainObject) {
return domainObject.type === 'my-type';
},
view: function (domainObject) {
return new MyView(domainObject);
}
});
```
### Adding a Root-level Object
In many cases, you'd like a certain object (or a certain hierarchy of
objects) to be accessible from the top level of the application (the
tree on the left-hand side of Open MCT.) It is typical to expose a telemetry
dictionary as a hierarchy of telemetry-providing domain objects in this
fashion.
To do so, use the [`addRoot`]{@link module:openmct.ObjectAPI#addRoot} method
of the [object API]{@link module:openmct.ObjectAPI}:
```
openmct.objects.addRoot({
identifier: { key: "my-key", namespace: "my-namespace" }
name: "My Root-level Object",
type: "my-type"
});
```
You can also remove this root-level object via its identifier:
```
openmct.objects.removeRoot({ key: "my-key", namespace: "my-namespace" });
```
### Adding Composition Providers
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 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:
```
openmct.composition.addProvider({
appliesTo: function (domainObject) {
return domainObject.type === 'my-type';
},
load: function (domainObject) {
return Promise.resolve(myDomainObjects);
}
});
```
### Adding Telemetry Providers
When connecting to a new telemetry source, you will want to register a new
[telemetry provider]{@link module:openmct.TelemetryAPI~TelemetryProvider}
with the [telemetry API]{@link module:openmct.TelemetryAPI#addProvider}:
```
openmct.telemetry.addProvider({
canProvideTelemetry: function (domainObject) {
return domainObject.type === 'my-type';
},
properties: function (domainObject) {
return [
{ key: 'value', name: "Temperature", units: "degC" },
{ key: 'time', name: "UTC" }
];
},
request: function (domainObject, options) {
var telemetryId = domainObject.myTelemetryId;
return myAdapter.request(telemetryId, options.start, options.end);
},
subscribe: function (domainObject, callback) {
var telemetryId = domainObject.myTelemetryId;
myAdapter.subscribe(telemetryId, callback);
return myAdapter.unsubscribe.bind(myAdapter, telemetryId, callback);
}
});
```
The implementations for `request` and `subscribe` can vary depending on the
nature of the endpoint which will provide telemetry. In the example above,
it is assumed that `myAdapter` contains the specific implementations
(HTTP requests, WebSocket connections, etc.) associated with some telemetry
source.
## Using Open MCT
When implementing new features, it is useful and sometimes necessary to
utilize functionality exposed by Open MCT.
### Retrieving Composition
To limit which objects are loaded at any given time, the composition of
a domain object must be requested asynchronously:
```
openmct.composition(myObject).load().then(function (childObjects) {
childObjects.forEach(doSomething);
});
```
### Support Common Gestures
Custom views may also want to support common gestures using the
[gesture API]{@link module:openmct.GestureAPI}. For instance, to make
a view (or part of a view) selectable:
```
openmct.gestures.selectable(myHtmlElement, myDomainObject);
```
### Working with Domain Objects
The [object API]{@link module:openmct.ObjectAPI} provides useful methods
for working with domain objects.
To make changes to a domain object, use the
[`mutate`]{@link module:openmct.ObjectAPI#mutate} method:
```
openmct.objects.mutate(myDomainObject, "name", "New name!");
```
Making modifications in this fashion allows other usages of the domain
object to remain up to date using the
[`observe`]{@link module:openmct.ObjectAPI#observe} method:
```
openmct.objects.observe(myDomainObject, "name", function (newName) {
myLabel.textContent = newName;
});
```
### Using Telemetry
Very often in Open MCT, you wish to work with telemetry data (for instance,
to display it in a custom visualization.)
### Synchronizing with the Time Conductor
Views which wish to remain synchronized with the state of Open MCT's
time conductor should utilize
[`openmct.conductor`]{@link module:openmct.TimeConductor}:
```
openmct.conductor.on('bounds', function (newBounds) {
requestTelemetry(newBounds.start, newBounds.end).then(displayTelemetry);
});
```
## Plugins
While you can register new features with Open MCT directly, it is generally
more useful to package these as a plugin. A plugin is a function that takes
[`openmct`]{@link module:openmct} as an argument, and performs configuration
upon `openmct` when invoked.
### Installing Plugins
To install plugins, use the [`install`]{@link module:openmct.MCT#install}
method:
```
openmct.install(myPlugin);
```
The plugin will be invoked to configure Open MCT before it is started.
### Writing Plugins
Plugins configure Open MCT, and should utilize the
[`openmct`]{@link module:openmct} module to do so, as summarized above in
"Configuring Open MCT" and "Using Open MCT" above.
### Distributing Plugins
Hosting or downloading plugins is outside of the scope of this documentation.
We recommend distributing plugins as UMD modules which export a single
function.

View File

@@ -20,6 +20,7 @@
"FileSaver.js": "^0.0.2",
"zepto": "^1.1.6",
"eventemitter3": "^1.2.0",
"lodash": "3.10.1"
"lodash": "3.10.1",
"almond": "~0.3.2"
}
}

65
composition-test.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Implementing a composition provider</title>
<script src="dist/main.js"></script>
</head>
<body>
<script>
var widgetParts = ['foo', 'bar', 'baz', 'bing', 'frobnak']
function fabricateName() {
return [
widgetParts[Math.floor(Math.random() * widgetParts.length)],
widgetParts[Math.floor(Math.random() * widgetParts.length)],
Math.floor(Math.random() * 1000)
].join('_');
}
MCT.type('example.widget-factory', new MCT.Type({
metadata: {
label: "Widget Factory",
glyph: "s",
description: "A factory for making widgets"
},
initialize: function (object) {
object.widgetCount = 5;
object.composition = [];
},
creatable: true,
form: [
{
name: "Widget Count",
control: "textfield",
key: "widgetCount",
property: "widgetCount",
required: true
}
]
}));
MCT.Composition.addProvider({
appliesTo: function (domainObject) {
return domainObject.type === 'example.widget-factory';
},
load: function (domainObject) {
var widgets = [];
while (widgets.length < domainObject.widgetCount) {
widgets.push({
name: fabricateName(),
key: {
namespace: 'widget-factory',
identifier: '' + widgets.length
}
});
}
return Promise.resolve(widgets);
}
});
MCT.run();
</script>
</body>
</html>

144
custom-view-react.html Normal file
View File

@@ -0,0 +1,144 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Implementing a Custom Type and View </title>
<script src="dist/main.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
</head>
<body>
<script type="text/babel">
// First, we're going to create the Todo List type, so that users can create
// todo lists.
MCT.type('example.todo', new MCT.Type({
metadata: {
label: "To-Do List",
glyph: "2",
description: "A list of things that need to be done."
},
initialize: function (object) {
object.tasks = [
{ description: "This is a task." }
];
},
creatable: true
}));
/*
Refresh the page, and you should be able to create new Todo Lists.
unfortunately, when you navigate to a Todo list, you see a blank page. let's
fix that by adding a main view for that todo list.
If you're wondering why this is commented out, well, it's because we'll
write a new version later.
*/
var Task = React.createClass({
render: function() {
return (
<li>
<input type="checkbox"
checked={this.props.checked}/>
<span>{this.props.description}</span>
</li>
);
}
});
var TaskList = React.createClass({
render: function () {
var taskNodes = this.props.tasks.map(function(task) {
return (
<Task checked={task.checked}
description={task.description}/>
);
});
return (
<ul>
{taskNodes}
</ul>
);
}
});
MCT.view(MCT.regions.main, {
canView: function (domainObject) {
return domainObject.type === 'example.todo';
},
view: function (domainObject) {
var mutableObject = MCT.Objects.getMutable(domainObject);
return {
show: function (container) {
ReactDOM.render(
<TaskList tasks={domainObject.tasks}/>,
container
);
mutableObject.on('tasks', function (tasks) {
ReactDOM.render(
<TaskList tasks={tasks}/>,
container
);
});
}
};
}
});
/*
Refresh the page and you should see a todo list with checkboxes! Now let's
Allow you to add tasks by mutating the object. We'll add a toolbar view to
do this.
*/
var TaskToolbar = React.createClass({
render: function () {
return (
<button onClick={this.props.addTask}>Add Task</button>
);
}
});
MCT.view(MCT.regions.toolbar, {
canView: function (domainObject) {
return domainObject.type === 'example.todo';
},
view: function (domainObject) {
var mutableObject = MCT.Objects.getMutable(domainObject);
function addTask(event) {
var description = prompt('Task description');
var tasks = mutableObject.get('tasks');
tasks.push({
description: description,
complete: false
});
mutableObject.set('tasks', tasks);
}
return {
show: function (container) {
ReactDOM.render(
<TaskToolbar addTask={addTask}/>,
container
);
},
}
}
});
/*
Refresh the page, edit the todo list, and you'll have a button that allows
you to add tasks! Unfortunately, new tasks don't show in the list. Why?
Well, if your view should update on mutation, you need to set up the correct
listeners. Let's update the TodoView we made earlier:
*/
MCT.run();
</script>
</body>
</html>

160
custom-view.html Normal file
View File

@@ -0,0 +1,160 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Implementing a Custom Type and View </title>
<script src="dist/main.js"></script>
</head>
<body>
<script>
// First, we're going to create the Todo List type, so that users can create
// todo lists.
MCT.type('example.todo', new MCT.Type({
metadata: {
label: "To-Do List",
glyph: "2",
description: "A list of things that need to be done."
},
initialize: function (object) {
object.tasks = [
{ description: "This is a task." }
];
},
creatable: true
}));
/*
Refresh the page, and you should be able to create new Todo Lists.
unfortunately, when you navigate to a Todo list, you see a blank page. let's
fix that by adding a main view for that todo list.
If you're wondering why this is commented out, well, it's because we'll
write a new version later.
*/
// MCT.view(MCT.regions.main, {
// canView: function (domainObject) {
// return domainObject.type === 'example.todo';
// },
// view: function (domainObject) {
// function renderTask(task) {
// return [
// '<li>',
// '<input type="checkbox"' + (task.complete ? ' checked="true"' : '') + '>',
// '<span>' + task.description + '</span>',
// '</li>'
// ].join('');
// };
//
// function renderTaskList() {
// return [
// '<ul>',
// domainObject.tasks.map(renderTask).join(''),
// '</ul>'
// ].join('');
// };
//
// return {
// show: function (container) {
// container.innerHTML = renderTaskList();
// }
// };
// }
// });
/*
Refresh the page and you should see a todo list with checkboxes! Now let's
Allow you to add tasks by mutating the object. We'll add a toolbar view to
do this.
*/
MCT.view(MCT.regions.toolbar, {
canView: function (domainObject) {
return domainObject.type === 'example.todo';
},
view: function (domainObject) {
var mutableObject = MCT.Objects.getMutable(domainObject);
function addTask(event) {
var description = prompt('Task description');
var tasks = mutableObject.get('tasks');
tasks.push({
description: description,
complete: false
});
mutableObject.set('tasks', tasks);
}
return {
show: function (container) {
container.addEventListener('click', addTask);
container.innerHTML = '<button>Add Task</button>';
},
destroy: function (container) {
container.removeEventListener('click', addTask);
}
}
}
});
/*
Refresh the page, edit the todo list, and you'll have a button that allows
you to add tasks! Unfortunately, new tasks don't show in the list. Why?
Well, if your view should update on mutation, you need to set up the correct
listeners. Let's update the TodoView we made earlier:
*/
MCT.view(MCT.regions.main, {
canView: function(domainObject) {
return domainObject.type === 'example.todo'
},
view: function (domainObject) {
var mutableObject = MCT.Objects.getMutable(domainObject);
function renderTask(task) {
return [
'<li>',
'<input type="checkbox"' + (task.complete ? ' checked="true"' : '') + '>',
'<span>' + task.description + '</span>',
'</li>'
].join('');
}
function renderTaskList(tasks) {
return [
'<ul>',
tasks.map(renderTask).join(''),
'</ul>'
].join('');
}
function onCheckboxChange(event) {
var checkbox = event.target;
var taskEl = checkbox.parentNode;
var taskList = taskEl.parentNode;
var taskIndex = [].slice.apply(taskList.children).indexOf(taskEl);
mutableObject.set('tasks[' + taskIndex + '].complete', checkbox.checked);
}
return {
show: function (container) {
container.innerHTML = renderTaskList(domainObject.tasks);
mutableObject.on('tasks', function (tasks) {
container.innerHTML = renderTaskList(tasks);
});
container.addEventListener('change', onCheckboxChange);
},
destroy: function () {
mutableObject.stopListening();
}
};
}
});
MCT.run();
</script>
</body>
</html>

View File

@@ -36,7 +36,7 @@ define([
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/notifications", {
legacyRegistry.register("example/msl-adapter", {
"name" : "Mars Science Laboratory Data Adapter",
"extensions" : {
"types": [

View File

@@ -21,40 +21,33 @@
*****************************************************************************/
/*global require,__dirname*/
var gulp = require('gulp'),
requirejsOptimize = require('gulp-requirejs-optimize'),
sourcemaps = require('gulp-sourcemaps'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
bourbon = require('node-bourbon'),
jshint = require('gulp-jshint'),
jscs = require('gulp-jscs'),
replace = require('gulp-replace-task'),
karma = require('karma'),
path = require('path'),
fs = require('fs'),
git = require('git-rev-sync'),
moment = require('moment'),
merge = require('merge-stream'),
project = require('./package.json'),
_ = require('lodash'),
paths = {
main: 'main.js',
dist: 'dist',
assets: 'dist/assets',
scss: ['./platform/**/*.scss', './example/**/*.scss'],
assets: [
'./{example,platform}/**/*.{css,css.map,png,svg,ico,woff,eot,ttf}'
],
scripts: [ 'main.js', 'platform/**/*.js', 'src/**/*.js' ],
specs: [ 'platform/**/*Spec.js', 'src/**/*Spec.js' ],
static: [
'index.html',
'platform/**/*',
'example/**/*',
'bower_components/**/*'
]
},
options = {
requirejsOptimize: {
name: paths.main.replace(/\.js$/, ''),
name: 'bower_components/almond/almond.js',
include: paths.main.replace('.js', ''),
wrap: {
startFile: "src/start.frag",
endFile: "src/end.frag"
},
mainConfigFile: paths.main,
wrapShim: true
},
@@ -63,7 +56,6 @@ var gulp = require('gulp'),
singleRun: true
},
sass: {
includePaths: bourbon.includePaths,
sourceComments: true
},
replace: {
@@ -77,6 +69,8 @@ var gulp = require('gulp'),
};
gulp.task('scripts', function () {
var requirejsOptimize = require('gulp-requirejs-optimize');
var replace = require('gulp-replace-task');
return gulp.src(paths.main)
.pipe(sourcemaps.init())
.pipe(requirejsOptimize(options.requirejsOptimize))
@@ -86,10 +80,16 @@ gulp.task('scripts', function () {
});
gulp.task('test', function (done) {
var karma = require('karma');
new karma.Server(options.karma, done).start();
});
gulp.task('stylesheets', function () {
var sass = require('gulp-sass');
var rename = require('gulp-rename');
var bourbon = require('node-bourbon');
options.sass.includePaths = bourbon.includePaths;
return gulp.src(paths.scss, {base: '.'})
.pipe(sourcemaps.init())
.pipe(sass(options.sass).on('error', sass.logError))
@@ -103,6 +103,9 @@ gulp.task('stylesheets', function () {
});
gulp.task('lint', function () {
var jshint = require('gulp-jshint');
var merge = require('merge-stream');
var nonspecs = paths.specs.map(function (glob) {
return "!" + glob;
}),
@@ -117,6 +120,8 @@ gulp.task('lint', function () {
});
gulp.task('checkstyle', function () {
var jscs = require('gulp-jscs');
return gulp.src(paths.scripts)
.pipe(jscs())
.pipe(jscs.reporter())
@@ -124,18 +129,20 @@ gulp.task('checkstyle', function () {
});
gulp.task('fixstyle', function () {
var jscs = require('gulp-jscs');
return gulp.src(paths.scripts, { base: '.' })
.pipe(jscs({ fix: true }))
.pipe(gulp.dest('.'));
});
gulp.task('static', ['stylesheets'], function () {
return gulp.src(paths.static, { base: '.' })
gulp.task('assets', ['stylesheets'], function () {
return gulp.src(paths.assets)
.pipe(gulp.dest(paths.dist));
});
gulp.task('watch', function () {
gulp.watch(paths.scss, ['stylesheets']);
return gulp.watch(paths.scss, ['stylesheets', 'assets']);
});
gulp.task('serve', function () {
@@ -143,9 +150,9 @@ gulp.task('serve', function () {
var app = require('./app.js');
});
gulp.task('develop', ['serve', 'stylesheets', 'watch']);
gulp.task('develop', ['serve', 'install', 'watch']);
gulp.task('install', [ 'static', 'scripts' ]);
gulp.task('install', [ 'assets', 'scripts' ]);
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);

View File

@@ -31,16 +31,13 @@
<script type="text/javascript">
require(['main'], function (mct) {
require([
'./tutorials/grootprovider/groots',
'./tutorials/todo/todo',
'./tutorials/todo/bundle',
'./example/imagery/bundle',
'./example/eventGenerator/bundle',
'./example/generator/bundle',
], function (grootify, todoPlugin) {
grootify(mct);
todoPlugin(mct);
mct.start();
'./example/generator/bundle'
], function (todoPlugin) {
mct.install(todoPlugin);
mct.run();
})
});
</script>
@@ -55,7 +52,5 @@
<div class="l-splash-holder s-splash-holder">
<div class="l-splash s-splash"></div>
</div>
<div ng-view></div>
</body>
</html>

57
main.js
View File

@@ -56,56 +56,31 @@ requirejs.config({
},
"zepto": {
"exports": "Zepto"
},
"lodash": {
"exports": "lodash"
}
}
});
define([
'./platform/framework/src/Main',
'legacyRegistry',
'./src/MCT',
'./platform/framework/bundle',
'./platform/core/bundle',
'./platform/representation/bundle',
'./platform/commonUI/about/bundle',
'./platform/commonUI/browse/bundle',
'./platform/commonUI/edit/bundle',
'./platform/commonUI/dialog/bundle',
'./platform/commonUI/formats/bundle',
'./platform/commonUI/general/bundle',
'./platform/commonUI/inspect/bundle',
'./platform/commonUI/mobile/bundle',
'./platform/commonUI/themes/espresso/bundle',
'./platform/commonUI/notification/bundle',
'./platform/containment/bundle',
'./platform/execution/bundle',
'./platform/exporters/bundle',
'./platform/telemetry/bundle',
'./platform/features/clock/bundle',
'./platform/features/imagery/bundle',
'./platform/features/layout/bundle',
'./platform/features/pages/bundle',
'./platform/features/plot/bundle',
'./platform/features/timeline/bundle',
'./platform/features/table/bundle',
'./platform/forms/bundle',
'./platform/identity/bundle',
'./platform/persistence/aggregator/bundle',
'./platform/persistence/local/bundle',
'./platform/persistence/queue/bundle',
'./platform/policy/bundle',
'./platform/entanglement/bundle',
'./platform/search/bundle',
'./platform/status/bundle',
'./platform/commonUI/regions/bundle'
], function (Main, legacyRegistry, MCT) {
'./src/defaultRegistry',
'./src/MCT'
], function (Main, defaultRegistry, MCT) {
var mct = new MCT();
mct.legacyRegistry = legacyRegistry;
mct.run = mct.start;
mct.legacyRegistry = defaultRegistry;
mct.run = function (domElement) {
if (!domElement) { domElement = document.body; }
var appDiv = document.createElement('div');
appDiv.setAttribute('ng-view', '');
appDiv.className = 'user-environ';
domElement.appendChild(appDiv);
mct.start();
};
mct.on('start', function () {
return new Main().run(legacyRegistry);
return new Main().run(defaultRegistry);
});
return mct;

64
object-provider.html Normal file
View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Groot Tutorial</title>
<script src="dist/main.js"></script>
</head>
<body>
<script>
// First, we need a source of objects, so we're going to define a few
// objects that we wish to expose. The first object is a folder which
// contains the other objects.
var GROOT_ROOT = {
name: 'I am groot',
type: 'folder',
composition: [
{
namespace: 'groot',
identifier: 'arms'
},
{
namespace: 'groot',
identifier: 'legs'
},
{
namespace: 'groot',
identifier: 'torso'
}
]
};
// Now, we will define an object provider. This will allow us to fetch the
// GROOT_ROOT object, plus any other objects in the `groot` namespace.
// For more info, see the Object API documentation.
MCT.Objects.addProvider('groot', {
// we'll only define a get function, objects from this provider will
// not be mutable.
get: function (key) {
if (key.identifier === 'groot') {
return Promise.resolve(GROOT_ROOT);
}
return Promise.resolve({
name: 'Groot\'s ' + key.identifier
});
}
});
// Finally, we need to add a "ROOT." This is an identifier for an object
// that Open MCT will load at run time and show at the top-level of the
// navigation tree.
MCT.Objects.addRoot({
namespace: 'groot',
identifier: 'groot'
});
MCT.run();
</script>
</body>
</html>

View File

@@ -39,6 +39,7 @@ define([
"text!./res/templates/items/items.html",
"text!./res/templates/browse/object-properties.html",
"text!./res/templates/browse/inspector-region.html",
"text!./res/templates/view-object.html",
'legacyRegistry'
], function (
BrowseController,
@@ -59,6 +60,7 @@ define([
itemsTemplate,
objectPropertiesTemplate,
inspectorRegionTemplate,
viewObjectTemplate,
legacyRegistry
) {
@@ -129,7 +131,7 @@ define([
"representations": [
{
"key": "view-object",
"templateUrl": "templates/view-object.html"
"template": viewObjectTemplate
},
{
"key": "browse-object",

View File

@@ -48,6 +48,7 @@ define([
"./src/directives/MCTSplitPane",
"./src/directives/MCTSplitter",
"./src/directives/MCTTree",
"./src/filters/ReverseFilter.js",
"text!./res/templates/bottombar.html",
"text!./res/templates/controls/action-button.html",
"text!./res/templates/controls/input-filter.html",
@@ -96,6 +97,7 @@ define([
MCTSplitPane,
MCTSplitter,
MCTTree,
ReverseFilter,
bottombarTemplate,
actionButtonTemplate,
inputFilterTemplate,
@@ -146,7 +148,8 @@ define([
"depends": [
"stylesheets[]",
"$document",
"THEME"
"THEME",
"ASSETS_PATH"
]
},
{
@@ -158,7 +161,7 @@ define([
],
"filters": [
{
"implementation": "filters/ReverseFilter.js",
"implementation": ReverseFilter,
"key": "reverse"
}
],
@@ -404,6 +407,11 @@ define([
"key": "THEME",
"value": "unspecified",
"priority": "fallback"
},
{
"key": "ASSETS_PATH",
"value": ".",
"priority": "fallback"
}
],
"containers": [

View File

@@ -38,7 +38,7 @@ define(
* @param $document Angular's jqLite-wrapped document element
* @param {string} activeTheme the theme in use
*/
function StyleSheetLoader(stylesheets, $document, activeTheme) {
function StyleSheetLoader(stylesheets, $document, activeTheme, assetPath) {
var head = $document.find('head'),
document = $document[0];
@@ -47,6 +47,7 @@ define(
// Create a link element, and construct full path
var link = document.createElement('link'),
path = [
assetPath,
stylesheet.bundle.path,
stylesheet.bundle.resources,
stylesheet.stylesheetUrl

View File

@@ -42,11 +42,19 @@ define(
function addWorker(worker) {
var key = worker.key;
if (!workerUrls[key]) {
workerUrls[key] = [
worker.bundle.path,
worker.bundle.sources,
worker.scriptUrl
].join("/");
if (worker.scriptUrl) {
workerUrls[key] = [
worker.bundle.path,
worker.bundle.sources,
worker.scriptUrl
].join("/");
} else if (worker.scriptText) {
var blob = new Blob(
[worker.scriptText],
{type: 'application/javascript'}
);
workerUrls[key] = URL.createObjectURL(blob);
}
sharedWorkers[key] = worker.shared;
}
}

View File

@@ -27,6 +27,9 @@ define([
"./src/controllers/TableOptionsController",
'../../commonUI/regions/src/Region',
'../../commonUI/browse/src/InspectorRegion',
"text!./res/templates/table-options-edit.html",
"text!./res/templates/rt-table.html",
"text!./res/templates/historical-table.html",
"legacyRegistry"
], function (
MCTTable,
@@ -35,6 +38,9 @@ define([
TableOptionsController,
Region,
InspectorRegion,
tableOptionsEditTemplate,
rtTableTemplate,
historicalTableTemplate,
legacyRegistry
) {
/**
@@ -128,7 +134,7 @@ define([
"name": "Historical Table",
"key": "table",
"glyph": "\ue604",
"templateUrl": "templates/historical-table.html",
"template": historicalTableTemplate,
"needs": [
"telemetry"
],
@@ -139,7 +145,7 @@ define([
"name": "Real-time Table",
"key": "rt-table",
"glyph": "\ue620",
"templateUrl": "templates/rt-table.html",
"template": rtTableTemplate,
"needs": [
"telemetry"
],
@@ -157,7 +163,7 @@ define([
"representations": [
{
"key": "table-options-edit",
"templateUrl": "templates/table-options-edit.html"
"template": tableOptionsEditTemplate
}
],
"stylesheets": [

View File

@@ -28,6 +28,7 @@ define([
"text!./res/templates/search-item.html",
"text!./res/templates/search.html",
"text!./res/templates/search-menu.html",
"text!./src/services/GenericSearchWorker.js",
'legacyRegistry'
], function (
SearchController,
@@ -37,6 +38,7 @@ define([
searchItemTemplate,
searchTemplate,
searchMenuTemplate,
searchWorkerText,
legacyRegistry
) {
@@ -114,7 +116,7 @@ define([
"workers": [
{
"key": "genericSearchWorker",
"scriptUrl": "services/GenericSearchWorker.js"
"scriptText": searchWorkerText
}
]
}

50
plugin-example.html Normal file
View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Implementing a basic plugin</title>
<script src="dist/main.js"></script>
</head>
<body>
<script>
function WebPlugin(websites) {
this.websites = websites;
var ROOTS = websites.reduce(function (rootMap, website) {
rootMap[website] = {
namespace: website,
identifier: 'page'
};
return rootMap;
}, {});
function installPlugin(MCT) {
Object.keys(ROOTS).forEach(function (rootUrl) {
MCT.Objects.addRoot(ROOTS[rootUrl]);
MCT.Objects.addProvider(rootUrl, {
get: function () {
return Promise.resolve({
type: 'example.page',
url: rootUrl,
name: rootUrl
});
}
});
});
}
return installPlugin;
}
var myWebPlugin = WebPlugin([
'http://www.wikipedia.org/',
'http://nasa.github.io/openmct'
]);
MCT.install(myWebPlugin);
MCT.run();
</script>
</body>
</html>

View File

@@ -1,9 +1,9 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* 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 Web is licensed under the Apache License, Version 2.0 (the
* 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.
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* 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.
@@ -24,10 +24,28 @@ define(function () {
function BundleRegistry() {
this.bundles = {};
this.knownBundles = {};
}
BundleRegistry.prototype.register = function (path, definition) {
this.bundles[path] = definition;
if (this.knownBundles.hasOwnProperty(path)) {
throw new Error('Cannot register bundle with duplicate path', path);
}
this.knownBundles[path] = definition;
};
BundleRegistry.prototype.enable = function (path) {
if (!this.knownBundles[path]) {
throw new Error('Unknown bundle ' + path);
}
this.bundles[path] = this.knownBundles[path];
};
BundleRegistry.prototype.disable = function (path) {
if (!this.bundles[path]) {
throw new Error('Tried to disable inactive bundle ' + path);
}
delete this.bundles[path];
};
BundleRegistry.prototype.contains = function (path) {
@@ -42,8 +60,14 @@ define(function () {
return Object.keys(this.bundles);
};
BundleRegistry.prototype.remove = function (path) {
BundleRegistry.prototype.remove = BundleRegistry.prototype.disable;
BundleRegistry.prototype.delete = function (path) {
if (!this.knownBundles[path]) {
throw new Error('Cannot remove Unknown Bundle ' + path);
}
delete this.bundles[path];
delete this.knownBundles[path];
};
return BundleRegistry;

View File

@@ -1,9 +1,9 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* 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 Web is licensed under the Apache License, Version 2.0 (the
* 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.
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* 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.
@@ -51,6 +51,7 @@ define(['./BundleRegistry'], function (BundleRegistry) {
beforeEach(function () {
testBundleDef = { someKey: "some value" };
bundleRegistry.register(testPath, testBundleDef);
bundleRegistry.enable(testPath);
});
it("lists registered bundles", function () {

View File

@@ -1,16 +1,199 @@
/*****************************************************************************
* 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([
'EventEmitter',
'legacyRegistry',
'uuid',
'./api/api',
'./api/objects/bundle'
'text!./adapter/templates/edit-object-replacement.html',
'./selection/Selection',
'./api/objects/object-utils',
'./ui/ViewRegistry'
], function (
EventEmitter,
legacyRegistry,
api
uuid,
api,
editObjectTemplate,
Selection,
objectUtils,
ViewRegistry
) {
/**
* Open MCT is an extensible web application for building mission
* control user interfaces. This module is itself an instance of
* [MCT]{@link module:openmct.MCT}, which provides an interface for
* configuring and executing the application.
*
* @exports openmct
*/
/**
* The Open MCT application. This may be configured by installing plugins
* or registering extensions before the application is started.
* @class MCT
* @memberof module:openmct
* @augments {EventEmitter}
*/
function MCT() {
EventEmitter.call(this);
this.legacyBundle = { extensions: {} };
this.legacyBundle = { extensions: {
services: [
{
key: "openmct",
implementation: function () {
return this;
}.bind(this)
}
]
} };
/**
* Tracks current selection state of the application.
* @private
*/
this.selection = new Selection();
/**
* MCT's time conductor, which may be used to synchronize view contents
* for telemetry- or time-based views.
* @type {module:openmct.TimeConductor}
* @memberof module:openmct.MCT#
* @name conductor
*/
this.conductor = new api.TimeConductor();
/**
* An interface for interacting with the composition of domain objects.
* The composition of a domain object is the list of other domain
* objects it "contains" (for instance, that should be displayed
* beneath it in the tree.)
*
* `composition` may be called as a function, in which case it acts
* as [`composition.get`]{@link module:openmct.CompositionAPI#get}.
*
* @type {module:openmct.CompositionAPI}
* @memberof module:openmct.MCT#
* @name composition
*/
this.composition = new api.CompositionAPI();
/**
* Registry for views of domain objects which should appear in the
* main viewing area.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name mainViews
*/
this.mainViews = new ViewRegistry();
/**
* Registry for views which should appear in the Inspector area.
* These views will be chosen based on selection state, so
* providers should be prepared to test arbitrary objects for
* viewability.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name inspectors
*/
this.inspectors = new ViewRegistry();
/**
* Registry for views which should appear in Edit Properties
* dialogs, and similar user interface elements used for
* modifying domain objects external to its regular views.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name propertyEditors
*/
this.propertyEditors = new ViewRegistry();
/**
* Registry for views which should appear in the status indicator area.
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name indicators
*/
this.indicators = new ViewRegistry();
/**
* Registry for views which should appear in the toolbar area while
* editing.
*
* These views will be chosen based on selection state, so
* providers should be prepared to test arbitrary objects for
* viewability.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name toolbars
*/
this.toolbars = new ViewRegistry();
/**
* Registry for domain object types which may exist within this
* instance of Open MCT.
*
* @type {module:openmct.TypeRegistry}
* @memberof module:openmct.MCT#
* @name types
*/
this.types = new api.TypeRegistry();
/**
* Utilities for attaching common behaviors to views.
*
* @type {module:openmct.GestureAPI}
* @memberof module:openmct.MCT#
* @name gestures
*/
this.gestures = new api.GestureAPI();
/**
* An interface for interacting with domain objects and the domain
* object hierarchy.
*
* @type {module:openmct.ObjectAPI}
* @memberof module:openmct.MCT#
* @name objects
*/
this.objects = new api.ObjectAPI();
/**
* An interface for retrieving and interpreting telemetry data associated
* with a domain object.
*
* @type {module:openmct.TelemetryAPI}
* @memberof module:openmct.MCT#
* @name telemetry
*/
this.telemetry = new api.TelemetryAPI();
this.TimeConductor = this.conductor; // compatibility for prototype
this.on('navigation', this.selection.clear.bind(this.selection));
}
MCT.prototype = Object.create(EventEmitter.prototype);
@@ -18,19 +201,75 @@ define([
Object.keys(api).forEach(function (k) {
MCT.prototype[k] = api[k];
});
MCT.prototype.MCT = MCT;
MCT.prototype.type = function (key, type) {
var legacyDef = type.toLegacyDefinition();
legacyDef.key = key;
this.legacyBundle.extensions.types =
this.legacyBundle.extensions.types || [];
this.legacyBundle.extensions.types.push(legacyDef);
MCT.prototype.legacyExtension = function (category, extension) {
this.legacyBundle.extensions[category] =
this.legacyBundle.extensions[category] || [];
this.legacyBundle.extensions[category].push(extension);
};
MCT.prototype.start = function () {
/**
* Set path to where assets are hosted. This should be the path to main.js.
* @memberof module:openmct.MCT#
* @method setAssetPath
*/
MCT.prototype.setAssetPath = function (path) {
this.legacyExtension('constants', {
key: "ASSETS_PATH",
value: path
});
};
/**
* Start running Open MCT. This should be called only after any plugins
* have been installed.
* @fires module:openmct.MCT~start
* @memberof module:openmct.MCT#
* @method start
* @param {HTMLElement} [domElement] the DOM element in which to run
* MCT; if undefined, MCT will be run in the body of the document
*/
MCT.prototype.start = function (domElement) {
if (!domElement) {
domElement = document.body;
}
var appDiv = document.createElement('div');
appDiv.setAttribute('ng-view', '');
appDiv.className = 'user-environ';
domElement.appendChild(appDiv);
this.legacyExtension('runs', {
depends: ['navigationService'],
implementation: function (navigationService) {
navigationService
.addListener(this.emit.bind(this, 'navigation'));
}.bind(this)
});
legacyRegistry.register('adapter', this.legacyBundle);
legacyRegistry.enable('adapter');
/**
* Fired by [MCT]{@link module:openmct.MCT} when the application
* is started.
* @event start
* @memberof module:openmct.MCT~
*/
this.emit('start');
};
/**
* Install a plugin in MCT.
*
* @param {Function} plugin a plugin install function which will be
* invoked with the mct instance.
* @memberof module:openmct.MCT#
*/
MCT.prototype.install = function (plugin) {
plugin(this);
};
return MCT;
});

View File

@@ -0,0 +1,57 @@
/*****************************************************************************
* 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([
'../../api/objects/object-utils'
], function (objectUtils) {
function ActionDialogDecorator(mct, actionService) {
this.mct = mct;
this.actionService = actionService;
}
ActionDialogDecorator.prototype.getActions = function (context) {
var mct = this.mct;
return this.actionService.getActions(context).map(function (action) {
if (action.dialogService) {
var domainObject = objectUtils.toNewFormat(
context.domainObject.getModel(),
objectUtils.parseKeyString(context.domainObject.getId())
);
var providers = mct.propertyEditors.get(domainObject);
if (providers.length > 0) {
action.dialogService = Object.create(action.dialogService);
action.dialogService.getUserInput = function (form, value) {
return new mct.Dialog(
providers[0].view(context.domainObject),
form.title
).show();
};
}
}
return action;
});
};
return ActionDialogDecorator;
});

127
src/adapter/bundle.js Normal file
View File

@@ -0,0 +1,127 @@
/*****************************************************************************
* 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([
'legacyRegistry',
'./actions/ActionDialogDecorator',
'./directives/MCTView',
'./services/Instantiate',
'./capabilities/APICapabilityDecorator',
'./policies/AdapterCompositionPolicy',
'./runs/AlternateCompositionInitializer'
], function (
legacyRegistry,
ActionDialogDecorator,
MCTView,
Instantiate,
APICapabilityDecorator,
AdapterCompositionPolicy,
AlternateCompositionInitializer
) {
legacyRegistry.register('src/adapter', {
"extensions": {
"directives": [
{
key: "mctView",
implementation: MCTView,
depends: [
"newViews[]",
"openmct"
]
}
],
services: [
{
key: "instantiate",
priority: "mandatory",
implementation: Instantiate,
depends: [
"capabilityService",
"identifierService",
"cacheService"
]
}
],
components: [
{
type: "decorator",
provides: "capabilityService",
implementation: APICapabilityDecorator,
depends: [
"$injector"
]
},
{
type: "decorator",
provides: "actionService",
implementation: ActionDialogDecorator,
depends: ["openmct"]
}
],
policies: [
{
category: "composition",
implementation: AdapterCompositionPolicy,
depends: ["openmct"]
}
],
runs: [
{
implementation: AlternateCompositionInitializer,
depends: ["openmct"]
}
],
licenses: [
{
"name": "almond",
"version": "0.3.3",
"description": "Lightweight RequireJS replacement for builds",
"author": "jQuery Foundation",
"website": "https://github.com/requirejs/almond",
"copyright": "Copyright jQuery Foundation and other contributors, https://jquery.org/",
"license": "license-mit",
"link": "https://github.com/requirejs/almond/blob/master/LICENSE"
},
{
"name": "lodash",
"version": "3.10.1",
"description": "Utility functions",
"author": "Dojo Foundation",
"website": "https://lodash.com",
"copyright": "Copyright 2012-2015 The Dojo Foundation",
"license": "license-mit",
"link": "https://raw.githubusercontent.com/lodash/lodash/3.10.1/LICENSE"
},
{
"name": "EventEmitter3",
"version": "1.2.0",
"description": "Event-driven programming support",
"author": "Arnout Kazemier",
"website": "https://github.com/primus/eventemitter3",
"copyright": "Copyright (c) 2014 Arnout Kazemier",
"license": "license-mit",
"link": "https://github.com/primus/eventemitter3/blob/1.2.0/LICENSE"
}
]
}
});
});

View File

@@ -0,0 +1,59 @@
/*****************************************************************************
* 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([
'./synchronizeMutationCapability',
'./AlternateCompositionCapability'
], function (
synchronizeMutationCapability,
AlternateCompositionCapability
) {
/**
* Overrides certain capabilities to keep consistency between old API
* and new API.
*/
function APICapabilityDecorator($injector, capabilityService) {
this.$injector = $injector;
this.capabilityService = capabilityService;
}
APICapabilityDecorator.prototype.getCapabilities = function (
model
) {
var capabilities = this.capabilityService.getCapabilities(model);
if (capabilities.mutation) {
capabilities.mutation =
synchronizeMutationCapability(capabilities.mutation);
}
if (AlternateCompositionCapability.appliesTo(model)) {
capabilities.composition = function (domainObject) {
return new AlternateCompositionCapability(this.$injector, domainObject);
}.bind(this);
}
return capabilities;
};
return APICapabilityDecorator;
});

View File

@@ -0,0 +1,107 @@
/*****************************************************************************
* 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 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.
*****************************************************************************/
/**
* Module defining AlternateCompositionCapability. Created by vwoeltje on 11/7/14.
*/
define([
'../../api/objects/object-utils'
], function (objectUtils) {
function AlternateCompositionCapability($injector, domainObject) {
this.domainObject = domainObject;
this.getDependencies = function () {
this.instantiate = $injector.get("instantiate");
this.contextualize = $injector.get("contextualize");
this.getDependencies = undefined;
this.openmct = $injector.get("openmct");
}.bind(this);
}
AlternateCompositionCapability.prototype.add = function (child, index) {
if (typeof index !== 'undefined') {
// At first glance I don't see a location in the existing
// codebase where add is called with an index. Won't support.
throw new Error(
'Composition Capability does not support adding at index'
);
}
function addChildToComposition(model) {
var existingIndex = model.composition.indexOf(child.getId());
if (existingIndex === -1) {
model.composition.push(child.getId());
}
}
return this.domainObject.useCapability(
'mutation',
addChildToComposition
)
.then(this.invoke.bind(this))
.then(function (children) {
return children.filter(function (c) {
return c.getId() === child.getId();
})[0];
});
};
AlternateCompositionCapability.prototype.contextualizeChild = function (
child
) {
if (this.getDependencies) {
this.getDependencies();
}
var keyString = objectUtils.makeKeyString(child.key);
var oldModel = objectUtils.toOldFormat(child);
var newDO = this.instantiate(oldModel, keyString);
return this.contextualize(newDO, this.domainObject);
};
AlternateCompositionCapability.prototype.invoke = function () {
var newFormatDO = objectUtils.toNewFormat(
this.domainObject.getModel(),
this.domainObject.getId()
);
if (this.getDependencies) {
this.getDependencies();
}
var collection = this.openmct.composition.get(newFormatDO);
return collection.load()
.then(function (children) {
collection.destroy();
return children.map(this.contextualizeChild, this);
}.bind(this));
};
AlternateCompositionCapability.appliesTo = function (model) {
// Will get replaced by a runs exception to properly
// bind to running openmct instance
return false;
};
return AlternateCompositionCapability;
}
);

View File

@@ -0,0 +1,49 @@
/*****************************************************************************
* 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 (
) {
/**
* Wraps the mutation capability and synchronizes the mutation
*/
function synchronizeMutationCapability(mutationConstructor) {
return function makeCapability(domainObject) {
var capability = mutationConstructor(domainObject);
var oldListen = capability.listen.bind(capability);
capability.listen = function (listener) {
return oldListen(function (newModel) {
capability.domainObject.model =
JSON.parse(JSON.stringify(newModel));
listener(newModel);
});
};
return capability;
};
}
return synchronizeMutationCapability;
});

View File

@@ -0,0 +1,87 @@
/*****************************************************************************
* 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([
'angular',
'./Region',
'../../api/objects/object-utils'
], function (
angular,
Region,
objectUtils
) {
function MCTView(newViews, PublicAPI) {
var definitions = {};
newViews.forEach(function (newView) {
definitions[newView.region] = definitions[newView.region] || {};
definitions[newView.region][newView.key] = newView.factory;
});
return {
restrict: 'E',
link: function (scope, element, attrs) {
var key, mctObject, regionId, region;
function maybeShow() {
if (!definitions[regionId] || !definitions[regionId][key] || !mctObject) {
return;
}
region.show(definitions[regionId][key].view(mctObject));
}
function setKey(k) {
key = k;
maybeShow();
}
function setObject(obj) {
mctObject = undefined;
PublicAPI.Objects.get(objectUtils.parseKeyString(obj.getId()))
.then(function (mobj) {
mctObject = mobj;
maybeShow();
});
}
function setRegionId(r) {
regionId = r;
maybeShow();
}
region = new Region(element[0]);
scope.$watch('key', setKey);
scope.$watch('region', setRegionId);
scope.$watch('mctObject', setObject);
},
scope: {
key: "=",
region: "=",
mctObject: "="
}
};
}
return MCTView;
});

View File

@@ -0,0 +1,45 @@
/*****************************************************************************
* 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 () {
function Region(element) {
this.activeView = undefined;
this.element = element;
}
Region.prototype.clear = function () {
if (this.activeView) {
this.activeView.destroy();
this.activeView = undefined;
}
};
Region.prototype.show = function (view) {
this.clear();
this.activeView = view;
if (this.activeView) {
this.activeView.show(this.element);
}
};
return Region;
});

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* 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 () {
function AdapterCompositionPolicy(mct) {
this.mct = mct;
}
AdapterCompositionPolicy.prototype.allow = function (
containerType,
childType
) {
var containerObject = containerType.getInitialModel();
var childObject = childType.getInitialModel();
containerObject.type = containerType.getKey();
childObject.type = childType.getKey();
var composition = this.mct.Composition(containerObject);
if (composition) {
return composition.canContain(childObject);
}
return true;
};
return AdapterCompositionPolicy;
});

View File

@@ -0,0 +1,36 @@
/*****************************************************************************
* 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 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.
*****************************************************************************/
define([
'../capabilities/AlternateCompositionCapability'
], function (AlternateCompositionCapability) {
// Present to work around the need for openmct to be used
// from AlternateCompositionCapability.appliesTo, even though it
// cannot be injected.
function AlternateCompositionInitializer(openmct) {
AlternateCompositionCapability.appliesTo = function (model) {
return !model.composition && !!openmct.composition.get(model);
};
}
return AlternateCompositionInitializer;
});

View File

@@ -0,0 +1,49 @@
/*****************************************************************************
* 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(
['../../../platform/core/src/objects/DomainObjectImpl'],
function (DomainObjectImpl) {
/**
* Overrides platform version of instantiate, passes Id with model such
* that capability detection can utilize new format domain objects.
*/
function Instantiate(
capabilityService,
identifierService,
cacheService
) {
return function (model, id) {
id = id || identifierService.generate();
var old_id = model.id;
model.id = id;
var capabilities = capabilityService.getCapabilities(model);
model.id = old_id;
cacheService.put(id, model);
return new DomainObjectImpl(id, model, capabilities);
};
}
return Instantiate;
}
);

View File

@@ -0,0 +1,46 @@
<div class="abs l-flex-col" ng-controller="EditObjectController as EditObjectController">
<div mct-before-unload="EditObjectController.getUnloadWarning()"
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"
class="flex-elem l-back"></mct-representation>
<mct-representation key="'object-header'"
mct-object="domainObject"
class="l-flex-row flex-elem grows object-header">
</mct-representation>
</div>
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
<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">
<div class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
<!-- Toolbar and Save/Cancel buttons -->
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
<mct-representation key="'adapted-view-TOOLBAR'"
mct-object="domainObject"
class="flex-elem grows">
</mct-representation>
<mct-representation key="'edit-action-buttons'"
mct-object="domainObject"
class='flex-elem conclude-editing'>
</mct-representation>
</div>
<mct-representation key="representation.selected.key"
mct-object="representation.selected.key && domainObject"
class="abs flex-elem grows object-holder-main scroll"
toolbar="toolbar">
</mct-representation>
</div><!--/ l-object-wrapper-inner -->
</div>
</div>

202
src/api/TimeConductor.js Normal file
View File

@@ -0,0 +1,202 @@
/*****************************************************************************
* 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(['EventEmitter'], function (EventEmitter) {
/**
* The public API for setting and querying time conductor state. The
* time conductor is the means by which the temporal bounds of a view
* are controlled. Time-sensitive views will typically respond to
* changes to bounds or other properties of the time conductor and
* update the data displayed based on the time conductor state.
*
* The TimeConductor extends the EventEmitter class. A number of events are
* fired when properties of the time conductor change, which are
* documented below.
* @interface
* @memberof module:openmct
*/
function TimeConductor() {
EventEmitter.call(this);
//The Time System
this.system = undefined;
//The Time Of Interest
this.toi = undefined;
this.boundsVal = {
start: undefined,
end: undefined
};
//Default to fixed mode
this.followMode = false;
}
TimeConductor.prototype = Object.create(EventEmitter.prototype);
/**
* Validate the given bounds. This can be used for pre-validation of
* bounds, for example by views validating user inputs.
* @param bounds The start and end time of the conductor.
* @returns {string | true} A validation error, or true if valid
* @memberof module:openmct.TimeConductor#
* @method validateBounds
*/
TimeConductor.prototype.validateBounds = function (bounds) {
if ((bounds.start === undefined) ||
(bounds.end === undefined) ||
isNaN(bounds.start) ||
isNaN(bounds.end)
) {
return "Start and end must be specified as integer values";
} else if (bounds.start > bounds.end) {
return "Specified start date exceeds end bound";
}
return true;
};
function throwOnError(validationResult) {
if (validationResult !== true) {
throw new Error(validationResult);
}
}
/**
* Get or set the follow mode of the time conductor. In follow mode the
* time conductor ticks, regularly updating the bounds from a timing
* source appropriate to the selected time system and mode of the time
* conductor.
* @fires module:openmct.TimeConductor~follow
* @param {boolean} followMode
* @returns {boolean}
* @memberof module:openmct.TimeConductor#
* @method follow
*/
TimeConductor.prototype.follow = function (followMode) {
if (arguments.length > 0) {
this.followMode = followMode;
/**
* The TimeConductor has toggled into or out of follow mode.
* @event follow
* @memberof module:openmct.TimeConductor~
* @property {boolean} followMode true if follow mode is
* enabled, otherwise false.
*/
this.emit('follow', this.followMode);
}
return this.followMode;
};
/**
* @typedef {Object} TimeConductorBounds
* @property {number} start The start time displayed by the time conductor in ms since epoch. Epoch determined by current time system
* @property {number} end The end time displayed by the time conductor in ms since epoch.
* @memberof module:openmct.TimeConductor~
*/
/**
* Get or set the start and end time of the time conductor. Basic validation
* of bounds is performed.
*
* @param {module:openmct.TimeConductorBounds~TimeConductorBounds} newBounds
* @throws {Error} Validation error
* @fires module:openmct.TimeConductor~bounds
* @returns {module:openmct.TimeConductorBounds~TimeConductorBounds}
* @memberof module:openmct.TimeConductor#
* @method bounds
*/
TimeConductor.prototype.bounds = function (newBounds) {
if (arguments.length > 0) {
throwOnError(this.validateBounds(newBounds));
this.boundsVal = newBounds;
/**
* The start time, end time, or both have been updated.
* @event bounds
* @memberof module:openmct.TimeConductor~
* @property {TimeConductorBounds} bounds
*/
this.emit('bounds', this.boundsVal);
}
return this.boundsVal;
};
/**
* Get or set the time system of the TimeConductor. Time systems determine
* units, epoch, and other aspects of time representation. When changing
* the time system in use, new valid bounds must also be provided.
* @param {TimeSystem} newTimeSystem
* @param {module:openmct.TimeConductor~TimeConductorBounds} bounds
* @fires module:openmct.TimeConductor~timeSystem
* @returns {TimeSystem} The currently applied time system
* @memberof module:openmct.TimeConductor#
* @method timeSystem
*/
TimeConductor.prototype.timeSystem = function (newTimeSystem, bounds) {
if (arguments.length >= 2) {
this.system = newTimeSystem;
/**
* The time system used by the time
* conductor has changed. A change in Time System will always be
* followed by a bounds event specifying new query bounds.
*
* @event module:openmct.TimeConductor~timeSystem
* @property {TimeSystem} The value of the currently applied
* Time System
* */
this.emit('timeSystem', this.system);
// Do something with bounds here. Try and convert between
// time systems? Or just set defaults when time system changes?
// eg.
this.bounds(bounds);
} else if (arguments.length === 1) {
throw new Error('Must set bounds when changing time system');
}
return this.system;
};
/**
* Get or set the Time of Interest. The Time of Interest is the temporal
* focus of the current view. It can be manipulated by the user from the
* time conductor or from other views.
* @fires module:openmct.TimeConductor~timeOfInterest
* @param newTOI
* @returns {number} the current time of interest
* @memberof module:openmct.TimeConductor#
* @method timeOfInterest
*/
TimeConductor.prototype.timeOfInterest = function (newTOI) {
if (arguments.length > 0) {
this.toi = newTOI;
/**
* The Time of Interest has moved.
* @event timeOfInterest
* @memberof module:openmct.TimeConductor~
* @property {number} Current time of interest
*/
this.emit('timeOfInterest', this.toi);
}
return this.toi;
};
return TimeConductor;
});

View File

@@ -0,0 +1,110 @@
/*****************************************************************************
* 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(['./TimeConductor'], function (TimeConductor) {
describe("The Time Conductor", function () {
var tc,
timeSystem,
bounds,
eventListener,
toi,
follow;
beforeEach(function () {
tc = new TimeConductor();
timeSystem = {};
bounds = {start: 0, end: 0};
eventListener = jasmine.createSpy("eventListener");
toi = 111;
follow = true;
});
it("Supports setting and querying of time of interest and and follow mode", function () {
expect(tc.timeOfInterest()).not.toBe(toi);
tc.timeOfInterest(toi);
expect(tc.timeOfInterest()).toBe(toi);
expect(tc.follow()).not.toBe(follow);
tc.follow(follow);
expect(tc.follow()).toBe(follow);
});
it("Allows setting of valid bounds", function () {
bounds = {start: 0, end: 1};
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds.bind(tc, bounds)).not.toThrow();
expect(tc.bounds()).toBe(bounds);
});
it("Disallows setting of invalid bounds", function () {
bounds = {start: 1, end: 0};
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds.bind(tc, bounds)).toThrow();
expect(tc.bounds()).not.toBe(bounds);
bounds = {start: 1};
expect(tc.bounds()).not.toBe(bounds);
expect(tc.bounds.bind(tc, bounds)).toThrow();
expect(tc.bounds()).not.toBe(bounds);
});
it("Allows setting of time system with bounds", function () {
expect(tc.timeSystem()).not.toBe(timeSystem);
expect(tc.timeSystem.bind(tc, timeSystem, bounds)).not.toThrow();
expect(tc.timeSystem()).toBe(timeSystem);
});
it("Disallows setting of time system without bounds", function () {
expect(tc.timeSystem()).not.toBe(timeSystem);
expect(tc.timeSystem.bind(tc, timeSystem)).toThrow();
expect(tc.timeSystem()).not.toBe(timeSystem);
});
it("Emits an event when time system changes", function () {
expect(eventListener).not.toHaveBeenCalled();
tc.on("timeSystem", eventListener);
tc.timeSystem(timeSystem, bounds);
expect(eventListener).toHaveBeenCalledWith(timeSystem);
});
it("Emits an event when time of interest changes", function () {
expect(eventListener).not.toHaveBeenCalled();
tc.on("timeOfInterest", eventListener);
tc.timeOfInterest(toi);
expect(eventListener).toHaveBeenCalledWith(toi);
});
it("Emits an event when bounds change", function () {
expect(eventListener).not.toHaveBeenCalled();
tc.on("bounds", eventListener);
tc.bounds(bounds);
expect(eventListener).toHaveBeenCalledWith(bounds);
});
it("Emits an event when follow mode changes", function () {
expect(eventListener).not.toHaveBeenCalled();
tc.on("follow", eventListener);
tc.follow(follow);
expect(eventListener).toHaveBeenCalledWith(follow);
});
});
});

View File

@@ -1,6 +1,29 @@
/*****************************************************************************
* 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 () {
/**
* @typedef TypeDefinition
* @memberof module:openmct.Type~
* @property {Metadata} metadata displayable metadata about this type
* @property {function (object)} [initialize] a function which initializes
* the model for new domain objects of this type
@@ -9,34 +32,27 @@ define(function () {
*/
/**
* A Type describes a kind of domain object that may appear or be
* created within Open MCT.
*
* @param {TypeDefinition} definition
* @constructor
* @param {module:opemct.Type~TypeDefinition} definition
* @class Type
* @memberof module:openmct
*/
function Type(definition) {
this.definition = definition;
}
/**
* Get a definition for this type that can be registered using the
* legacy bundle format.
* @private
* Check if a domain object is an instance of this type.
* @param domainObject
* @returns {boolean} true if the domain object is of this type
* @memberof module:openmct.Type#
* @method check
*/
Type.prototype.toLegacyDefinition = function () {
var def = {};
def.name = this.definition.metadata.label;
def.glyph = this.definition.metadata.glyph;
def.description = this.definition.metadata.description;
if (this.definition.initialize) {
def.model = {};
this.definition.initialize(def.model);
}
if (this.definition.creatable) {
def.features = ['creation'];
}
return def;
Type.prototype.check = function (domainObject) {
// Depends on assignment from MCT.
return domainObject.type === this.key;
};
return Type;

View File

@@ -1,12 +1,52 @@
/*****************************************************************************
* 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([
'./Type',
'./objects/ObjectAPI'
'./TimeConductor',
'./objects/ObjectAPI',
'./composition/CompositionAPI',
'./types/TypeRegistry',
'./ui/Dialog',
'./ui/GestureAPI',
'./telemetry/TelemetryAPI'
], function (
Type,
ObjectAPI
TimeConductor,
ObjectAPI,
CompositionAPI,
TypeRegistry,
Dialog,
GestureAPI,
TelemetryAPI
) {
return {
Type: Type,
Objects: ObjectAPI
TimeConductor: TimeConductor,
ObjectAPI: ObjectAPI,
CompositionAPI: CompositionAPI,
Dialog: Dialog,
TypeRegistry: TypeRegistry,
GestureAPI: GestureAPI,
TelemetryAPI: TelemetryAPI
};
});

View File

@@ -0,0 +1,136 @@
/*****************************************************************************
* 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([
'lodash',
'EventEmitter',
'./DefaultCompositionProvider',
'./CompositionCollection'
], function (
_,
EventEmitter,
DefaultCompositionProvider,
CompositionCollection
) {
/**
* An interface for interacting with the composition of domain objects.
* The composition of a domain object is the list of other domain objects
* it "contains" (for instance, that should be displayed beneath it
* in the tree.)
*
* @interface CompositionAPI
* @returns {module:openmct.CompositionCollection}
* @memberof module:openmct
*/
function CompositionAPI() {
this.registry = [];
this.policies = [];
this.addProvider(new DefaultCompositionProvider());
}
/**
* Add a composition provider.
*
* Plugins can add new composition providers to change the loading
* behavior for certain domain objects.
*
* @method addProvider
* @param {module:openmct.CompositionProvider} provider the provider to add
* @memberof module:openmct.CompositionAPI#
*/
CompositionAPI.prototype.addProvider = function (provider) {
this.registry.unshift(provider);
};
/**
* Retrieve the composition (if any) of this domain object.
*
* @method get
* @returns {module:openmct.CompositionCollection}
* @memberof module:openmct.CompositionAPI#
*/
CompositionAPI.prototype.get = function (domainObject) {
var provider = _.find(this.registry, function (p) {
return p.appliesTo(domainObject);
});
if (!provider) {
return;
}
return new CompositionCollection(domainObject, provider);
};
/**
* A composition policy is a function which either allows or disallows
* placing one object in another's composition.
*
* Open MCT's policy model requires consensus, so any one policy may
* reject composition by returning false. As such, policies should
* generally be written to return true in the default case.
*
* @callback CompositionPolicy
* @memberof module:openmct.CompositionAPI~
* @param {module:openmct.DomainObject} containingObject the object which
* would act as a container
* @param {module:openmct.DomainObject} containedObject the object which
* would be contained
* @returns {boolean} false if this composition should be disallowed
*/
/**
* Add a composition policy. Composition policies may disallow domain
* objects from containing other domain objects.
*
* @method addPolicy
* @param {module:openmct.CompositionAPI~CompositionPolicy} policy
* the policy to add
* @memberof module:openmct.CompositionAPI#
*/
CompositionAPI.prototype.addPolicy = function (policy) {
this.policies.push(policy);
};
/**
* Check whether or not a domain object is allowed to contain another
* domain object.
*
* @private
* @method checkPolicy
* @param {module:openmct.DomainObject} containingObject the object which
* would act as a container
* @param {module:openmct.DomainObject} containedObject the object which
* would be contained
* @returns {boolean} false if this composition should be disallowed
* @param {module:openmct.CompositionAPI~CompositionPolicy} policy
* the policy to add
* @memberof module:openmct.CompositionAPI#
*/
CompositionAPI.prototype.checkPolicy = function (container, containee) {
return this.policies.every(function (policy) {
return policy(container, containee);
});
};
return CompositionAPI;
});

View File

@@ -0,0 +1,231 @@
/*****************************************************************************
* 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([
'EventEmitter',
'lodash',
'../objects/object-utils'
], function (
EventEmitter,
_,
objectUtils
) {
/**
* A CompositionCollection represents the list of domain objects contained
* by another domain object. It provides methods for loading this
* list asynchronously, and for modifying this list.
*
* @interface CompositionCollection
* @param {module:openmct.DomainObject} domainObject the domain object
* whose composition will be contained
* @param {module:openmct.CompositionProvider} provider the provider
* to use to retrieve other domain objects
* @param {module:openmct.CompositionAPI} api the composition API, for
* policy checks
* @memberof module:openmct
* @augments EventEmitter
*/
function CompositionCollection(domainObject, provider, api) {
EventEmitter.call(this);
this.domainObject = domainObject;
this.provider = provider;
this.api = api;
if (this.provider.on) {
this.provider.on(
this.domainObject,
'add',
this.onProviderAdd,
this
);
this.provider.on(
this.domainObject,
'remove',
this.onProviderRemove,
this
);
}
}
CompositionCollection.prototype = Object.create(EventEmitter.prototype);
CompositionCollection.prototype.onProviderAdd = function (child) {
this.add(child, true);
};
CompositionCollection.prototype.onProviderRemove = function (child) {
this.remove(child, true);
};
/**
* Get the index of a domain object within this composition. If the
* domain object is not contained here, -1 will be returned.
*
* A call to [load]{@link module:openmct.CompositionCollection#load}
* must have resolved before using this method.
*
* @param {module:openmct.DomainObject} child the domain object for which
* an index should be retrieved
* @returns {number} the index of that domain object
* @memberof module:openmct.CompositionCollection#
* @name indexOf
*/
CompositionCollection.prototype.indexOf = function (child) {
return _.findIndex(this.loadedChildren, function (other) {
return objectUtils.equals(child, other);
});
};
/**
* Get the index of a domain object within this composition.
*
* A call to [load]{@link module:openmct.CompositionCollection#load}
* must have resolved before using this method.
*
* @param {module:openmct.DomainObject} child the domain object for which
* containment should be checked
* @returns {boolean} true if the domain object is contained here
* @memberof module:openmct.CompositionCollection#
* @name contains
*/
CompositionCollection.prototype.contains = function (child) {
return this.indexOf(child) !== -1;
};
/**
* Check if a domain object can be added to this composition.
*
* @param {module:openmct.DomainObject} child the domain object to add
* @memberof module:openmct.CompositionCollection#
* @name canContain
*/
CompositionCollection.prototype.canContain = function (domainObject) {
return this.api.checkPolicy(this.domainObject, domainObject);
};
/**
* Add a domain object to this composition.
*
* A call to [load]{@link module:openmct.CompositionCollection#load}
* must have resolved before using this method.
*
* @param {module:openmct.DomainObject} child the domain object to add
* @param {boolean} skipMutate true if the underlying provider should
* not be updated
* @memberof module:openmct.CompositionCollection#
* @name add
*/
CompositionCollection.prototype.add = function (child, skipMutate) {
if (!this.loadedChildren) {
throw new Error("Must load composition before you can add!");
}
if (!this.canContain(child)) {
throw new Error("This object cannot contain that object.");
}
if (this.contains(child)) {
if (skipMutate) {
return; // don't add twice, don't error.
}
throw new Error("Unable to add child: already in composition");
}
this.loadedChildren.push(child);
this.emit('add', child);
if (!skipMutate) {
// add after we have added.
this.provider.add(this.domainObject, child);
}
};
/**
* Load the domain objects in this composition.
*
* @returns {Promise.<Array.<module:openmct.DomainObject>>} a promise for
* the domain objects in this composition
* @memberof {module:openmct.CompositionCollection#}
* @name load
*/
CompositionCollection.prototype.load = function () {
return this.provider.load(this.domainObject)
.then(function (children) {
this.loadedChildren = [];
children.map(function (c) {
this.add(c, true);
}, this);
this.emit('load');
return this.loadedChildren.slice();
}.bind(this));
};
/**
* Remove a domain object from this composition.
*
* A call to [load]{@link module:openmct.CompositionCollection#load}
* must have resolved before using this method.
*
* @param {module:openmct.DomainObject} child the domain object to remove
* @param {boolean} skipMutate true if the underlying provider should
* not be updated
* @memberof module:openmct.CompositionCollection#
* @name remove
*/
CompositionCollection.prototype.remove = function (child, skipMutate) {
if (!this.contains(child)) {
if (skipMutate) {
return;
}
throw new Error("Unable to remove child: not found in composition");
}
var index = this.indexOf(child);
var removed = this.loadedChildren.splice(index, 1)[0];
this.emit('remove', index, child);
if (!skipMutate) {
// trigger removal after we have internally removed it.
this.provider.remove(this.domainObject, removed);
}
};
/**
* Stop using this composition collection. This will release any resources
* associated with this collection.
* @name destroy
* @memberof module:openmct.CompositionCollection#
*/
CompositionCollection.prototype.destroy = function () {
if (this.provider.off) {
this.provider.off(
this.domainObject,
'add',
this.onProviderAdd,
this
);
this.provider.off(
this.domainObject,
'remove',
this.onProviderRemove,
this
);
}
};
return CompositionCollection;
});

View File

@@ -0,0 +1,150 @@
/*****************************************************************************
* 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([
'lodash',
'EventEmitter',
'../objects/ObjectAPI',
'../objects/object-utils'
], function (
_,
EventEmitter,
ObjectAPI,
objectUtils
) {
/**
* A CompositionProvider provides the underlying implementation of
* composition-related behavior for certain types of domain object.
*
* @interface CompositionProvider
* @memberof module:openmct
* @augments EventEmitter
*/
function makeEventName(domainObject, event) {
return event + ':' + objectUtils.makeKeyString(domainObject.key);
}
function DefaultCompositionProvider() {
EventEmitter.call(this);
}
DefaultCompositionProvider.prototype =
Object.create(EventEmitter.prototype);
/**
* Check if this provider should be used to load composition for a
* particular domain object.
* @param {module:openmct.DomainObject} domainObject the domain object
* to check
* @returns {boolean} true if this provider can provide
* composition for a given domain object
* @memberof module:openmct.CompositionProvider#
* @method appliesTo
*/
DefaultCompositionProvider.prototype.appliesTo = function (domainObject) {
return !!domainObject.composition;
};
/**
* Load any domain objects contained in the composition of this domain
* object.
* @param {module:openmct.DomainObjcet} domainObject the domain object
* for which to load composition
* @returns {Promise.<Array.<module:openmct.DomainObject>>} a promise for
* the domain objects in this composition
* @memberof module:openmct.CompositionProvider#
* @method load
*/
DefaultCompositionProvider.prototype.load = function (domainObject) {
return Promise.all(domainObject.composition.map(ObjectAPI.get));
};
DefaultCompositionProvider.prototype.on = function (
domainObject,
event,
listener,
context
) {
// these can likely be passed through to the mutation service instead
// of using an eventemitter.
this.addListener(
makeEventName(domainObject, event),
listener,
context
);
};
DefaultCompositionProvider.prototype.off = function (
domainObject,
event,
listener,
context
) {
// these can likely be passed through to the mutation service instead
// of using an eventemitter.
this.removeListener(
makeEventName(domainObject, event),
listener,
context
);
};
/**
* Remove a domain object from another domain object's composition.
*
* This method is optional; if not present, adding to a domain object's
* composition using this provider will be disallowed.
*
* @param {module:openmct.DomainObject} domainObject the domain object
* which should have its composition modified
* @param {module:openmct.DomainObject} child the domain object to remove
* @memberof module:openmct.CompositionProvider#
* @method remove
*/
DefaultCompositionProvider.prototype.remove = function (domainObject, child) {
// TODO: this needs to be synchronized via mutation
var index = domainObject.composition.indexOf(child);
domainObject.composition.splice(index, 1);
this.emit(makeEventName(domainObject, 'remove'), child);
};
/**
* Add a domain object to another domain object's composition.
*
* This method is optional; if not present, adding to a domain object's
* composition using this provider will be disallowed.
*
* @param {module:openmct.DomainObject} domainObject the domain object
* which should have its composition modified
* @param {module:openmct.DomainObject} child the domain object to add
* @memberof module:openmct.CompositionProvider#
* @method add
*/
DefaultCompositionProvider.prototype.add = function (domainObject, child) {
// TODO: this needs to be synchronized via mutation
domainObject.composition.push(child.key);
this.emit(makeEventName(domainObject, 'add'), child);
};
return DefaultCompositionProvider;
});

View File

@@ -1,19 +1,77 @@
/*****************************************************************************
* 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([
'./object-utils',
'./ObjectAPI'
'./objectEventEmitter'
], function (
utils,
ObjectAPI
objectEventEmitter
) {
function ObjectServiceProvider(objectService, instantiate) {
function ObjectServiceProvider(objectService, instantiate, topic) {
this.objectService = objectService;
this.instantiate = instantiate;
this.generalTopic = topic('mutation');
this.bridgeEventBuses();
}
/**
* Bridges old and new style mutation events to provide compatibility between the two APIs
* @private
*/
ObjectServiceProvider.prototype.bridgeEventBuses = function () {
var removeGeneralTopicListener;
var handleLegacyMutation;
var handleMutation = function (newStyleObject) {
var keyString = utils.makeKeyString(newStyleObject.key);
var oldStyleObject = this.instantiate(utils.toOldFormat(newStyleObject), keyString);
// Don't trigger self
removeGeneralTopicListener();
oldStyleObject.getCapability('mutation').mutate(function () {
return utils.toOldFormat(newStyleObject);
});
removeGeneralTopicListener = this.generalTopic.listen(handleLegacyMutation);
}.bind(this);
handleLegacyMutation = function (legacyObject) {
var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId());
//Don't trigger self
objectEventEmitter.off('mutation', handleMutation);
objectEventEmitter.emit(newStyleObject.key.identifier + ":*", newStyleObject);
objectEventEmitter.on('mutation', handleMutation);
}.bind(this);
objectEventEmitter.on('mutation', handleMutation);
removeGeneralTopicListener = this.generalTopic.listen(handleLegacyMutation);
};
ObjectServiceProvider.prototype.save = function (object) {
var key = object.key,
keyString = utils.makeKeyString(key),
newObject = this.instantiate(utils.toOldFormat(object), keyString);
var key = object.key;
return object.getCapability('persistence')
.persist()
@@ -30,21 +88,21 @@ define([
var keyString = utils.makeKeyString(key);
return this.objectService.getObjects([keyString])
.then(function (results) {
var model = JSON.parse(JSON.stringify(results[keyString].getModel()));
var model = results[keyString].getModel();
return utils.toNewFormat(model, key);
});
};
// 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(ROOTS, instantiate, objectService) {
function LegacyObjectAPIInterceptor(openmct, ROOTS, instantiate, topic, objectService) {
this.getObjects = function (keys) {
var results = {},
promises = keys.map(function (keyString) {
var key = utils.parseKeyString(keyString);
return ObjectAPI.get(key)
return openmct.objects.get(key)
.then(function (object) {
object = utils.toOldFormat(object)
object = utils.toOldFormat(object);
results[keyString] = instantiate(object, keyString);
});
});
@@ -55,12 +113,12 @@ define([
});
};
ObjectAPI._supersecretSetFallbackProvider(
new ObjectServiceProvider(objectService, instantiate)
openmct.objects.supersecretSetFallbackProvider(
new ObjectServiceProvider(objectService, instantiate, topic)
);
ROOTS.forEach(function (r) {
ObjectAPI.addRoot(utils.parseKeyString(r.id));
openmct.objects.addRoot(utils.parseKeyString(r.id));
});
return this;

View File

@@ -0,0 +1,90 @@
/*****************************************************************************
* 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([
'lodash',
'./objectEventEmitter'
], function (
_,
objectEventEmitter
) {
var ANY_OBJECT_EVENT = "mutation";
/**
* The MutableObject wraps a DomainObject and provides getters and
* setters for
* @param eventEmitter
* @param object
* @interface MutableObject
*/
function MutableObject(object) {
this.object = object;
this.unlisteners = [];
}
function qualifiedEventName(object, eventName) {
return [object.key.identifier, eventName].join(':');
}
MutableObject.prototype.stopListening = function () {
this.unlisteners.forEach(function (unlisten) {
unlisten();
});
};
/**
* Observe changes to this domain object.
* @param {string} path the property to observe
* @param {Function} callback a callback to invoke when new values for
* this property are observed
* @method on
* @memberof module:openmct.MutableObject#
*/
MutableObject.prototype.on = function (path, callback) {
var fullPath = qualifiedEventName(this.object, path);
objectEventEmitter.on(fullPath, callback);
this.unlisteners.push(objectEventEmitter.off.bind(objectEventEmitter, fullPath, callback));
};
/**
* Modify this domain object.
* @param {string} path the property to modify
* @param {*} value the new value for this property
* @method set
* @memberof module:openmct.MutableObject#
*/
MutableObject.prototype.set = function (path, value) {
_.set(this.object, path, value);
_.set(this.object, 'modified', Date.now());
//Emit event specific to property
objectEventEmitter.emit(qualifiedEventName(this.object, path), value);
//Emit wildcare event
objectEventEmitter.emit(qualifiedEventName(this.object, '*'), this.object);
//Emit a general "any object" event
objectEventEmitter.emit(ANY_OBJECT_EVENT, this.object);
};
return MutableObject;
});

View File

@@ -1,67 +1,133 @@
/*****************************************************************************
* 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([
'lodash',
'./object-utils'
'./object-utils',
'./MutableObject'
], function (
_,
utils
utils,
MutableObject
) {
/**
Object API. Intercepts the existing object API while also exposing
A new Object API.
* Utilities for loading, saving, and manipulating domain objects.
* @interface ObjectAPI
* @memberof module:openmct
* @implements {module:openmct.ObjectProvider}
*/
MCT.objects.get('mine')
.then(function (root) {
console.log(root);
MCT.objects.getComposition(root)
.then(function (composition) {
console.log(composition)
})
});
*/
function ObjectAPI() {
this.providers = {};
this.rootRegistry = [];
this.rootProvider = {
'get': function () {
return Promise.resolve({
name: 'The root object',
type: 'root',
composition: this.rootRegistry
});
}.bind(this)
};
}
var Objects = {},
ROOT_REGISTRY = [],
PROVIDER_REGISTRY = {},
FALLBACK_PROVIDER;
Objects._supersecretSetFallbackProvider = function (p) {
FALLBACK_PROVIDER = p;
};
// Root provider is hardcoded in; can't be skipped.
var RootProvider = {
'get': function () {
return Promise.resolve({
name: 'The root object',
type: 'root',
composition: ROOT_REGISTRY
});
}
ObjectAPI.prototype.supersecretSetFallbackProvider = function (p) {
this.fallbackProvider = p;
};
// Retrieve the provider for a given key.
function getProvider(key) {
ObjectAPI.prototype.getProvider = function (key) {
if (key.identifier === 'ROOT') {
return RootProvider;
return this.rootProvider;
}
return PROVIDER_REGISTRY[key.namespace] || FALLBACK_PROVIDER;
return this.providers[key.namespace] || this.fallbackProvider;
};
Objects.addProvider = function (namespace, provider) {
PROVIDER_REGISTRY[namespace] = provider;
/**
* Register a new object provider for a particular namespace.
*
* @param {string} namespace the namespace for which to provide objects
* @param {module:openmct.ObjectProvider} provider the provider which
* will handle loading domain objects from this namespace
* @memberof {module:openmct.ObjectAPI#}
* @name addProvider
*/
ObjectAPI.prototype.addProvider = function (namespace, provider) {
this.providers[namespace] = provider;
};
/**
* Provides the ability to read, write, and delete domain objects.
*
* When registering a new object provider, all methods on this interface
* are optional.
*
* @interface ObjectProvider
* @memberof module:openmct
*/
/**
* Save this domain object in its current state.
*
* @method save
* @memberof module:openmct.ObjectProvider#
* @param {module:openmct.DomainObject} domainObject the domain object to
* save
* @returns {Promise} a promise which will resolve when the domain object
* has been saved, or be rejected if it cannot be saved
*/
/**
* Delete this domain object.
*
* @method delete
* @memberof module:openmct.ObjectProvider#
* @param {module:openmct.DomainObject} domainObject the domain object to
* delete
* @returns {Promise} a promise which will resolve when the domain object
* has been deleted, or be rejected if it cannot be deleted
*/
/**
* Get a domain object.
*
* @method get
* @memberof module:openmct.ObjectProvider#
* @param {string} key the key for the domain object to load
* @returns {Promise} a promise which will resolve when the domain object
* has been saved, or be rejected if it cannot be saved
*/
[
'save',
'delete',
'get'
].forEach(function (method) {
Objects[method] = function () {
ObjectAPI.prototype[method] = function () {
var key = arguments[0],
provider = getProvider(key);
provider = this.getProvider(key);
if (!provider) {
throw new Error('No Provider Matched');
@@ -75,12 +141,26 @@ define([
};
});
Objects.addRoot = function (key) {
ROOT_REGISTRY.unshift(key);
/**
* Add a root-level object.
* @param {module:openmct.DomainObject} domainObject the root-level object
* to add.
* @method addRoot
* @memberof module:openmct.ObjectAPI#
*/
ObjectAPI.prototype.addRoot = function (key) {
this.rootRegistry.unshift(key);
};
Objects.removeRoot = function (key) {
ROOT_REGISTRY = ROOT_REGISTRY.filter(function (k) {
/**
* Remove a root-level object.
* @param {module:openmct.ObjectAPI~Identifier} id the identifier of the
* root-level object to remove.
* @method removeRoot
* @memberof module:openmct.ObjectAPI#
*/
ObjectAPI.prototype.removeRoot = function (key) {
this.rootRegistry = this.rootRegistry.filter(function (k) {
return (
k.identifier !== key.identifier ||
k.namespace !== key.namespace
@@ -88,5 +168,67 @@ define([
});
};
return Objects;
/**
* Modify a domain object.
* @param {module:openmct.DomainObject} object the object to mutate
* @param {string} path the property to modify
* @param {*} value the new value for this property
* @method mutate
* @memberof module:openmct.ObjectAPI#
*/
ObjectAPI.prototype.mutate = function (domainObject, path, value) {
return new MutableObject(domainObject).set(path, value);
};
/**
* Observe changes to a domain object.
* @param {module:openmct.DomainObject} object the object to observe
* @param {string} path the property to observe
* @param {Function} callback a callback to invoke when new values for
* this property are observed
* @method observe
* @memberof module:openmct.ObjectAPI#
*/
ObjectAPI.prototype.observe = function (domainObject, path, callback) {
var mutableObject = new MutableObject(domainObject);
mutableObject.on(path, callback);
return mutableObject.stopListening.bind(mutableObject);
};
/**
* Uniquely identifies a domain object.
*
* @typedef Identifier
* @memberof module:openmct.ObjectAPI~
* @property {string} namespace the namespace to/from which this domain
* object should be loaded/stored.
* @property {string} key a unique identifier for the domain object
* within that namespace
*/
/**
* A domain object is an entity of relevance to a user's workflow, that
* should appear as a distinct and meaningful object within the user
* interface. Examples of domain objects are folders, telemetry sensors,
* and so forth.
*
* A few common properties are defined for domain objects. Beyond these,
* individual types of domain objects may add more as they see fit.
*
* @property {module:openmct.ObjectAPI~Identifier} identifier a key/namespace pair which
* uniquely identifies this domain object
* @property {string} type the type of domain object
* @property {string} name the human-readable name for this domain object
* @property {string} [creator] the user name of the creator of this domain
* object
* @property {number} [modified] the time, in milliseconds since the UNIX
* epoch, at which this domain object was last modified
* @property {module:openmct.ObjectAPI~Identifier[]} [composition] if
* present, this will be used by the default composition provider
* to load domain objects
* @typedef DomainObject
* @memberof module:openmct
*/
return ObjectAPI;
});

View File

@@ -1,100 +0,0 @@
# Object API - Overview
The object API provides methods for fetching domain objects.
# Keys
Keys are a composite identifier that is used to create and persist objects. Ex:
```javascript
{
namespace: 'elastic',
identifier: 'myIdentifier'
}
```
In old MCT days, we called this an "id", and we encoded it in a single string.
The above key would encode into the identifier, `elastic:myIdentifier`.
When interacting with the API you will be dealing with key objects.
# Configuring the Object API
The following methods should be used before calling run. They allow you to
configure the persistence space of MCT.
* `MCT.objects.addRoot(key)` -- add a "ROOT" to Open MCT by specifying it's
key.
* `MCT.objects.removeRoot(key)` -- Remove a "ROOT" from Open MCT by key.
* `MCT.objects.addProvider(namespace, provider)` -- register an object provider
for a specific namespace. See below for documentation on the provider
interface.
# Using the object API
The object API provides methods for getting, saving, and deleting objects.
* MCT.objects.get(key) -> returns promise for an object
* MCT.objects.save(object) -> returns promise that is resolved when object
has been saved
* MCT.objects.delete(object) -> returns promise that is resolved when object has
been deleted
## Configuration Example: Adding a groot
The following example adds a new root object for groot and populates it with
some pieces of groot.
```javascript
var ROOT_KEY = {
namespace: 'groot',
identifier: 'groot'
};
var GROOT_ROOT = {
name: 'I am groot',
type: 'folder',
composition: [
{
namespace: 'groot',
identifier: 'arms'
},
{
namespace: 'groot',
identifier: 'legs'
},
{
namespace: 'groot',
identifier: 'torso'
}
]
};
var GrootProvider = {
get: function (key) {
if (key.identifier === 'groot') {
return Promise.resolve(GROOT_ROOT);
}
return Promise.resolve({
name: 'Groot\'s ' + key.identifier
});
}
};
mct.Objects.addRoot(ROOT_KEY);
mct.Objects.addProvider('groot', GrootProvider);
```
### Making a custom provider:
All methods on the provider interface are optional, so you do not need
to modify them.
* `provider.get(key)` -> promise for a domain object.
* `provider.save(domainObject)` -> returns promise that is fulfilled when object
has been saved.
* `provider.delete(domainObject)` -> returns promise that is fulfilled when
object has been deleted.

View File

@@ -1,9 +1,9 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* 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 Web is licensed under the Apache License, Version 2.0 (the
* 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.
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* 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.
@@ -39,8 +39,10 @@ define([
priority: "mandatory",
implementation: LegacyObjectAPIInterceptor,
depends: [
"openmct",
"roots[]",
"instantiate"
"instantiate",
"topic"
]
}
]

View File

@@ -1,3 +1,25 @@
/*****************************************************************************
* 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 (
@@ -12,13 +34,26 @@ define([
}
var namespace = '',
identifier = key;
for (var i = 0, escaped = false, len=key.length; i < len; i++) {
if (key[i] === ":" && !escaped) {
namespace = key.slice(0, i);
identifier = key.slice(i + 1);
break;
for (var i = 0, escaped = false; i < key.length; i++) {
if (escaped) {
escaped = false;
namespace += key[i];
} else {
if (key[i] === "\\") {
escaped = true;
} else if (key[i] === ":") {
// namespace = key.slice(0, i);
identifier = key.slice(i + 1);
break;
}
namespace += key[i];
}
}
if (key === namespace) {
namespace = '';
}
return {
namespace: namespace,
identifier: identifier
@@ -42,6 +77,7 @@ define([
// Converts composition to use key strings instead of keys
var toOldFormat = function (model) {
model = JSON.parse(JSON.stringify(model));
delete model.key;
if (model.composition) {
model.composition = model.composition.map(makeKeyString);
@@ -51,6 +87,7 @@ define([
// converts composition to use keys instead of key strings
var toNewFormat = function (model, key) {
model = JSON.parse(JSON.stringify(model));
model.key = key;
if (model.composition) {
model.composition = model.composition.map(parseKeyString);
@@ -58,10 +95,15 @@ define([
return model;
};
var equals = function (a, b) {
return makeKeyString(a.key) === makeKeyString(b.key);
};
return {
toOldFormat: toOldFormat,
toNewFormat: toNewFormat,
makeKeyString: makeKeyString,
parseKeyString: parseKeyString
parseKeyString: parseKeyString,
equals: equals
};
});

View File

@@ -0,0 +1,32 @@
/*****************************************************************************
* 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([
"EventEmitter"
], function (
EventEmitter
) {
/**
* Provides a singleton event bus for sharing between objects.
*/
return new EventEmitter();
});

View File

@@ -0,0 +1,319 @@
/*****************************************************************************
* 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([
'lodash',
'EventEmitter'
], function (
_,
EventEmitter
) {
/**
* A LimitEvaluator may be used to detect when telemetry values
* have exceeded nominal conditions.
*
* @interface LimitEvaluator
* @memberof module:openmct.TelemetryAPI~
*/
/**
* Check for any limit violations associated with a telemetry datum.
* @method evaluate
* @param {*} datum the telemetry datum to evaluate
* @param {TelemetryProperty} the property to check for limit violations
* @memberof module:openmct.TelemetryAPI~LimitEvaluator
* @returns {module:openmct.TelemetryAPI~LimitViolation} metadata about
* the limit violation, or undefined if a value is within limits
*/
/**
* A violation of limits defined for a telemetry property.
* @typedef LimitViolation
* @memberof {module:openmct.TelemetryAPI~}
* @property {string} cssclass the class (or space-separated classes) to
* apply to display elements for values which violate this limit
* @property {string} name the human-readable name for the limit violation
*/
/**
* A TelemetryFormatter converts telemetry values for purposes of
* display as text.
*
* @interface TelemetryFormatter
* @memberof module:openmct.TelemetryAPI~
*/
/**
* Retrieve the 'key' from the datum and format it accordingly to
* telemetry metadata in domain object.
*
* @method format
* @memberof module:openmct.TelemetryAPI~TelemetryFormatter#
*/
// format map is a placeholder until we figure out format service.
var FORMAT_MAP = {
generic: function (range) {
return function (datum) {
return datum[range.key];
};
},
enum: function (range) {
var enumMap = _.indexBy(range.enumerations, 'value');
return function (datum) {
try {
return enumMap[datum[range.valueKey]].text;
} catch (e) {
return datum[range.valueKey];
}
};
}
};
FORMAT_MAP.number =
FORMAT_MAP.float =
FORMAT_MAP.integer =
FORMAT_MAP.ascii =
FORMAT_MAP.generic;
/**
* Describes a property which would be found in a datum of telemetry
* associated with a particular domain object.
*
* @typedef TelemetryProperty
* @memberof module:openmct.TelemetryAPI~
* @property {string} key the name of the property in the datum which
* contains this telemetry value
* @property {string} name the human-readable name for this property
* @property {string} [units] the units associated with this property
* @property {boolean} [temporal] true if this property is a timestamp, or
* may be otherwise used to order telemetry in a time-like
* fashion; default is false
* @property {boolean} [numeric] true if the values for this property
* can be interpreted plainly as numbers; default is true
* @property {boolean} [enumerated] true if this property may have only
* certain specific values; default is false
* @property {string} [values] for enumerated states, an ordered list
* of possible values
*/
/**
* Describes and bounds requests for telemetry data.
*
* @typedef TelemetryRequest
* @memberof module:openmct.TelemetryAPI~
* @property {string} sort the key of the property to sort by. This may
* be prefixed with a "+" or a "-" sign to sort in ascending
* or descending order respectively. If no prefix is present,
* ascending order will be used.
* @property {*} start the lower bound for values of the sorting property
* @property {*} end the upper bound for values of the sorting property
* @property {string[]} strategies symbolic identifiers for strategies
* (such as `minmax`) which may be recognized by providers;
* these will be tried in order until an appropriate provider
* is found
*/
/**
* Provides telemetry data. To connect to new data sources, new
* TelemetryProvider implementations should be
* [registered]{@link module:openmct.TelemetryAPI#addProvider}.
*
* @interface TelemetryProvider
* @memberof module:openmct.TelemetryAPI~
*/
/**
* An interface for retrieving telemetry data associated with a domain
* object.
*
* @interface TelemetryAPI
* @augments module:openmct.TelemetryAPI~TelemetryProvider
* @memberof module:openmct
*/
function TelemetryAPI() {
this.providersByStrategy = {};
this.defaultProviders = [];
}
/**
* Check if this provider can supply telemetry data associated with
* this domain object.
*
* @method canProvideTelemetry
* @param {module:openmct.DomainObject} domainObject the object for
* which telemetry would be provided
* @returns {boolean} true if telemetry can be provided
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
TelemetryAPI.prototype.canProvideTelemetry = function (domainObject) {
return this.defaultProviders.some(function (provider) {
return provider.canProvideTelemetry(domainObject);
});
};
/**
* Register a telemetry provider with the telemetry service. This
* allows you to connect alternative telemetry sources.
* @method addProvider
* @memberof module:openmct.TelemetryAPI#
* @param {module:openmct.TelemetryAPI~TelemetryProvider} provider the new
* telemetry provider
* @param {string} [strategy] the request strategy supported by
* this provider. If omitted, this will be used as a
* default provider (when no strategy is requested or no
* matching strategy is found.)
*/
TelemetryAPI.prototype.addProvider = function (provider, strategy) {
if (!strategy) {
this.defaultProviders.push(provider);
} else {
this.providersByStrategy[strategy] =
this.providersByStrategy[strategy] || [];
this.providersByStrategy[strategy].push(provider);
}
};
/**
* @private
*/
TelemetryAPI.prototype.findProvider = function (domainObject, strategy) {
function supportsDomainObject(provider) {
return provider.canProvideTelemetry(domainObject);
}
if (strategy) {
var eligibleProviders =
(this.providersByStrategy[strategy] || [])
.filter(supportsDomainObject);
if (eligibleProviders.length > 0) {
return eligibleProviders[0];
}
}
return this.defaultProviders.filter(supportsDomainObject)[0];
};
/**
* Request historical telemetry for a domain object.
* The `options` argument allows you to specify filters
* (start, end, etc.), sort order, and strategies for retrieving
* telemetry (aggregation, latest available, etc.).
*
* @method request
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
* @param {module:openmct.DomainObject} domainObject the object
* which has associated telemetry
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
* options for this historical request
* @returns {Promise.<object[]>} a promise for an array of
* telemetry data
*/
TelemetryAPI.prototype.request = function (domainObject, options) {
var provider = this.findProvider(domainObject, options.strategy);
return provider ?
provider.request(domainObject, options) :
Promise.reject([]);
};
/**
* Subscribe to realtime telemetry for a specific domain object.
* The callback will be called whenever data is received from a
* realtime provider.
*
* @method subscribe
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
* @param {module:openmct.DomainObject} domainObject the object
* which has associated telemetry
* @param {Function} callback the callback to invoke with new data, as
* it becomes available
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
* options for this request
* @returns {Function} a function which may be called to terminate
* the subscription
*/
/**
* Get a list of all telemetry properties defined for this
* domain object.
*
* @param {module:openmct.DomainObject} domainObject the domain
* object for which to request telemetry
* @returns {module:openmct.TelemetryAPI~TelemetryProperty[]}
* telemetry metadata
* @method properties
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
/**
* Telemetry formatters help you format telemetry values for
* display. Under the covers, they use telemetry metadata to
* interpret your telemetry data, and then they use the format API
* to format that data for display.
*
* This method is optional.
* If a provider does not implement this method, it is presumed
* that all telemetry associated with this domain object can
* be formatted correctly by string coercion.
*
* @param {module:openmct.DomainObject} domainObject the domain
* object for which to format telemetry
* @returns {module:openmct.TelemetryAPI~TelemetryFormatter}
* @method formatter
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
/**
* Get a limit evaluator for this domain object.
* Limit Evaluators help you evaluate limit and alarm status of individual telemetry datums for display purposes without having to interact directly with the Limit API.
*
* This method is optional.
* If a provider does not implement this method, it is presumed
* that no limits are defined for this domain object's telemetry.
*
* @param {module:openmct.DomainObject} domainObject the domain
* object for which to evaluate limits
* @returns {module:openmct.TelemetryAPI~LimitEvaluator}
* @method limitEvaluator
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
_.forEach({
subscribe: undefined,
properties: [],
formatter: undefined,
limitEvaluator: undefined
}, function (defaultValue, method) {
TelemetryAPI.prototype[method] = function (domainObject) {
var provider = this.findProvider(domainObject);
return provider ?
provider[method].apply(provider, arguments) :
defaultValue;
};
});
return TelemetryAPI;
});

View File

@@ -0,0 +1,45 @@
/*****************************************************************************
* 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([
'./TelemetryAPI',
'legacyRegistry'
], function (
TelemetryAPI,
legacyRegistry
) {
legacyRegistry.register('api/telemetry-api', {
name: 'Telemetry API',
description: 'The public Telemetry API',
extensions: {
runs: [
{
key: "TelemetryAPI",
implementation: TelemetryAPI,
depends: [
'formatService'
]
}
]
}
});
});

View File

@@ -0,0 +1,51 @@
/*****************************************************************************
* 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 () {
/**
* A TypeRegistry maintains the definitions for different types
* that domain objects may have.
* @interface TypeRegistry
* @memberof module:openmct
*/
function TypeRegistry() {
this.types = {};
}
/**
* Register a new type of view.
*
* @param {string} typeKey a string identifier for this type
* @param {module:openmct.Type} type the type to add
* @method addProvider
* @memberof module:openmct.TypeRegistry#
*/
TypeRegistry.prototype.addType = function (typeKey, type) {
this.types[typeKey] = type;
};
return TypeRegistry;
});

107
src/api/ui/Dialog.js Normal file
View File

@@ -0,0 +1,107 @@
/*****************************************************************************
* 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(['text!./dialog.html', 'zepto'], function (dialogTemplate, $) {
/**
* A dialog may be displayed to show blocking content to users.
* @param {module:openmct.View} view the view to show in the dialog
* @param {string} [title] the title for this dialog
* @constructor
* @memberof module:openmct
*/
function Dialog(view, title) {
this.view = view;
this.title = title;
this.showing = false;
this.enabledState = true;
}
/**
* Display this dialog.
* @returns {Promise} a promise that will be resolved if the user
* chooses "OK", an rejected if the user chooses "cancel"
* @method show
* @memberof module:openmct.Dialog#
*/
Dialog.prototype.show = function () {
if (this.showing) {
throw new Error("Dialog already showing.");
}
var $body = $('body');
var $dialog = $(dialogTemplate);
var $contents = $dialog.find('.contents .editor');
var $close = $dialog.find('.close');
var $ok = $dialog.find('.ok');
var $cancel = $dialog.find('.cancel');
if (this.title) {
$dialog.find('.title').text(this.title);
}
$body.append($dialog);
this.view.show($contents[0]);
this.$dialog = $dialog;
this.$ok = $ok;
this.showing = true;
[$ok, $cancel, $close].forEach(function ($button) {
$button.on('click', this.hide.bind(this));
}.bind(this));
return new Promise(function (resolve, reject) {
$ok.on('click', resolve);
$cancel.on('click', reject);
$close.on('click', reject);
});
};
Dialog.prototype.hide = function () {
if (!this.showing) {
return;
}
this.$dialog.remove();
this.view.destroy();
this.showing = false;
};
/**
* Get or set the "enabled" state of the OK button for this dialog.
* @param {boolean} [state] true to enable, false to disable
* @returns {boolean} true if enabled, false if disabled
* @method enabled
* @memberof module:openmct.Dialog#
*/
Dialog.prototype.enabled = function (state) {
if (state !== undefined) {
this.enabledState = state;
if (this.showing) {
this.$ok.toggleClass('disabled', !state);
}
}
return this.enabledState;
};
return Dialog;
});

68
src/api/ui/GestureAPI.js Normal file
View File

@@ -0,0 +1,68 @@
/*****************************************************************************
* 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 () {
/**
* Allows support for common user actions to be attached to views.
* @interface GestureAPI
* @memberof module:openmct
*/
function GestureAPI(selectGesture, contextMenuGesture) {
this.selectGesture = selectGesture;
this.contextMenuGesture = contextMenuGesture;
}
/**
* Designate an HTML element as selectable, and associated with a
* particular object.
*
* @param {HTMLElement} htmlElement the element to make selectable
* @param {*} item the object which should become selected when this
* element is clicked.
* @returns {Function} a function to remove selectability from this
* HTML element.
* @method selectable
* @memberof module:openmct.GestureAPI#
*/
GestureAPI.prototype.selectable = function (htmlElement, item) {
return this.selectGesture.apply(htmlElement, item);
};
/**
* Designate an HTML element as having a context menu associated with
* the provided item.
*
* @private
* @param {HTMLElement} htmlElement the element to make selectable
* @param {*} item the object for which a context menu should appear
* @returns {Function} a function to remove this geture from this
* HTML element.
* @method selectable
* @memberof module:openmct.GestureAPI#
*/
GestureAPI.prototype.contextMenu = function (htmlElement, item) {
return this.contextMenuGesture.apply(htmlElement, item);
};
return GestureAPI;
});

21
src/api/ui/dialog.html Normal file
View File

@@ -0,0 +1,21 @@
<div class="abs overlay">
<div class="abs blocker"></div>
<div class="abs holder">
<a class="clk-icon icon ui-symbol close">x</a>
<div class="abs contents">
<div class="abs top-bar">
<div class="title"></div>
<div class="hint"></div>
</div>
<div class='abs editor'>
</div>
<div class="abs bottom-bar">
<a class='s-btn major ok'>OK</a>
<a class='s-btn cancel'>Cancel</a>
</div>
</div>
</div>
</div>

135
src/defaultRegistry.js Normal file
View File

@@ -0,0 +1,135 @@
/*****************************************************************************
* 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([
'legacyRegistry',
'../src/adapter/bundle',
'../src/api/objects/bundle',
'../example/builtins/bundle',
'../example/composite/bundle',
'../example/eventGenerator/bundle',
'../example/export/bundle',
'../example/extensions/bundle',
'../example/forms/bundle',
'../example/generator/bundle',
'../example/identity/bundle',
'../example/imagery/bundle',
'../example/mobile/bundle',
'../example/msl/bundle',
'../example/notifications/bundle',
'../example/persistence/bundle',
'../example/plotOptions/bundle',
'../example/policy/bundle',
'../example/profiling/bundle',
'../example/scratchpad/bundle',
'../example/taxonomy/bundle',
'../example/worker/bundle',
'../platform/commonUI/about/bundle',
'../platform/commonUI/browse/bundle',
'../platform/commonUI/dialog/bundle',
'../platform/commonUI/edit/bundle',
'../platform/commonUI/formats/bundle',
'../platform/commonUI/general/bundle',
'../platform/commonUI/inspect/bundle',
'../platform/commonUI/mobile/bundle',
'../platform/commonUI/notification/bundle',
'../platform/commonUI/regions/bundle',
'../platform/commonUI/themes/espresso/bundle',
'../platform/commonUI/themes/snow/bundle',
'../platform/containment/bundle',
'../platform/core/bundle',
'../platform/entanglement/bundle',
'../platform/execution/bundle',
'../platform/exporters/bundle',
'../platform/features/clock/bundle',
'../platform/features/conductor/bundle',
'../platform/features/imagery/bundle',
'../platform/features/layout/bundle',
'../platform/features/pages/bundle',
'../platform/features/plot/bundle',
'../platform/features/static-markup/bundle',
'../platform/features/table/bundle',
'../platform/features/timeline/bundle',
'../platform/forms/bundle',
'../platform/framework/bundle',
'../platform/framework/src/load/Bundle',
'../platform/identity/bundle',
'../platform/persistence/aggregator/bundle',
'../platform/persistence/couch/bundle',
'../platform/persistence/elastic/bundle',
'../platform/persistence/local/bundle',
'../platform/persistence/queue/bundle',
'../platform/policy/bundle',
'../platform/representation/bundle',
'../platform/search/bundle',
'../platform/status/bundle',
'../platform/telemetry/bundle'
], function (legacyRegistry) {
var DEFAULTS = [
'src/adapter',
'src/api/objects',
'platform/framework',
'platform/core',
'platform/representation',
'platform/commonUI/about',
'platform/commonUI/browse',
'platform/commonUI/edit',
'platform/commonUI/dialog',
'platform/commonUI/formats',
'platform/commonUI/general',
'platform/commonUI/inspect',
'platform/commonUI/mobile',
'platform/commonUI/themes/espresso',
'platform/commonUI/notification',
'platform/containment',
'platform/execution',
'platform/exporters',
'platform/telemetry',
'platform/features/clock',
'platform/features/imagery',
'platform/features/layout',
'platform/features/pages',
'platform/features/plot',
'platform/features/timeline',
'platform/features/table',
'platform/forms',
'platform/identity',
'platform/persistence/aggregator',
'platform/persistence/local',
'platform/persistence/queue',
'platform/policy',
'platform/entanglement',
'platform/search',
'platform/status',
'platform/commonUI/regions'
];
DEFAULTS.forEach(function (bundlePath) {
legacyRegistry.enable(bundlePath);
});
return legacyRegistry;
});

3
src/end.frag Normal file
View File

@@ -0,0 +1,3 @@
return require('main');
}));

View File

@@ -1,9 +1,9 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* 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 Web is licensed under the Apache License, Version 2.0 (the
* 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.
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* 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.

View File

@@ -1,9 +1,9 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* 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 Web is licensed under the Apache License, Version 2.0 (the
* 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.
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* 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.

View File

@@ -0,0 +1,78 @@
/*****************************************************************************
* 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(['zepto'], function ($) {
/**
* @typedef Context
* @property {*} item
* @property {HTMLElement} element
* @property {Context} parent the containing context (may be undefined)
* @memberof module:openmct
*/
function ContextManager() {
this.counter = 0;
this.contexts = {};
}
ContextManager.prototype.nextId = function () {
this.counter += 1;
return "context-" + this.counter;
};
ContextManager.prototype.context = function (item, htmlElement) {
var $element = $(htmlElement);
var id = $element.attr('data-context') || this.nextId();
$element.attr('data-context', id);
if (this.contexts[id] && this.contexts[id].item !== item) {
this.release(htmlElement);
}
if (!this.contexts[id]) {
var $parent = $element.closest('[data-context]');
var parentId = $parent.attr('data-context');
var parentContext = parentId ? this.contexts[parentId] : undefined;
this.contexts[id] = {
item: item,
element: htmlElement,
parent: parentContext
};
}
return this.contexts[id];
};
ContextManager.prototype.release = function (htmlElement) {
var $element = $(htmlElement);
var id = $element.attr('data-context');
if (id) {
delete this.contexts[id];
$element.removeAttr('data-context');
}
};
return ContextManager;
});

View File

@@ -0,0 +1,58 @@
/*****************************************************************************
* 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(['zepto'], function ($) {
function HoverGesture(hoverManager) {
this.hoverManager = hoverManager;
}
HoverGesture.prototype.apply = function (htmlElement) {
var $element = $(htmlElement);
var hoverManager = this.hoverManager;
function update() {
$(hoverManager.all()).removeClass('hovering');
$(hoverManager.top()).addClass('hovering');
}
function enter() {
hoverManager.add(htmlElement);
update();
}
function leave() {
hoverManager.remove(htmlElement);
update();
}
$element.on('mouseenter', enter);
$element.on('mouseleave', leave);
return function () {
leave();
$element.off('mouseenter', enter);
$element.off('mouseleave', leave);
}.bind(this);
};
return HoverGesture;
});

View File

@@ -0,0 +1,60 @@
/*****************************************************************************
* 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(['zepto'], function ($) {
function SelectGesture(selection, contextManager) {
this.selection = selection;
this.contextManager = contextManager;
}
SelectGesture.prototype.apply = function (htmlElement, item) {
var $element = $(htmlElement);
var contextManager = this.contextManager;
var selection = this.selection;
var path = contextManager.path(item, htmlElement);
function select() {
selection.add(path);
}
function change() {
var selected = selection.primary();
$element.toggleClass(
'selected',
selected && path.matches(selected)
);
}
$element.addClass('selectable');
$element.on('click', select);
selection.on('change', change);
change(); // Initialize
return function () {
contextManager.release(htmlElement);
$element.off('click', select);
selection.off('change', change);
};
};
return SelectGesture;
});

View File

@@ -0,0 +1,69 @@
/*****************************************************************************
* 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(['EventEmitter'], function (EventEmitter) {
/**
* Manages selection state for Open MCT
* @private
*/
function Selection() {
EventEmitter.call(this);
this.selected = [];
}
Selection.prototype = Object.create(EventEmitter.prototype);
Selection.prototype.add = function (context) {
this.clear(); // Only allow single select as initial simplification
this.selected.push(context);
this.emit('change');
};
Selection.prototype.remove = function (path) {
this.selected = this.selected.filter(function (otherPath) {
return !path.matches(otherPath);
});
this.emit('change');
};
Selection.prototype.contains = function (path) {
return this.selected.some(function (otherPath) {
return path.matches(otherPath);
});
};
Selection.prototype.clear = function () {
this.selected = [];
this.emit('change');
};
Selection.prototype.primary = function () {
return this.selected[this.selected.length - 1];
};
Selection.prototype.all = function () {
return this.selected;
};
return Selection;
});

39
src/start.frag Normal file
View File

@@ -0,0 +1,39 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* Open MCT https://nasa.github.io/openmct/
* Version @@version
* Built @@timestamp
* Revision @@revision
* Branch @@branch
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.MCT = factory();
}
}(this, function() {

152
src/ui/ViewRegistry.js Normal file
View File

@@ -0,0 +1,152 @@
/*****************************************************************************
* 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 () {
/**
* A ViewRegistry maintains the definitions for different kinds of views
* that may occur in different places in the user interface.
* @interface ViewRegistry
* @memberof module:openmct
*/
function ViewRegistry() {
this.providers = [];
}
/**
* @private for platform-internal use
* @param {*} item the object to be viewed
* @returns {module:openmct.ViewProvider[]} any providers
* which can provide views of this object
*/
ViewRegistry.prototype.get = function (item) {
return this.providers.filter(function (provider) {
return provider.canView(item);
});
};
/**
* Register a new type of view.
*
* @param {module:openmct.ViewProvider} provider the provider for this view
* @method addProvider
* @memberof module:openmct.ViewRegistry#
*/
ViewRegistry.prototype.addProvider = function (provider) {
this.providers.push(provider);
};
/**
* A View is used to provide displayable content, and to react to
* associated life cycle events.
*
* @name View
* @interface
* @memberof module:openmct
*/
/**
* Populate the supplied DOM element with the contents of this view.
*
* View implementations should use this method to attach any
* listeners or acquire other resources that are necessary to keep
* the contents of this view up-to-date.
*
* @param {HTMLElement} container the DOM element to populate
* @method show
* @memberof module:openmct.View#
*/
/**
* Release any resources associated with this view.
*
* View implementations should use this method to detach any
* listeners or release other resources that are no longer necessary
* once a view is no longer used.
*
* @method destroy
* @memberof module:openmct.View#
*/
/**
* Exposes types of views in Open MCT.
*
* @interface ViewProvider
* @memberof module:openmct
*/
/**
* Check if this provider can supply views for a domain object.
*
* When called by Open MCT, this may include additional arguments
* which are on the path to the object to be viewed; for instance,
* when viewing "A Folder" within "My Items", this method will be
* invoked with "A Folder" (as a domain object) as the first argument,
* and "My Items" as the second argument.
*
* @method canView
* @memberof module:openmct.ViewProvider#
* @param {module:openmct.DomainObject} domainObject the domain object
* to be viewed
* @returns {boolean} true if this domain object can be viewed using
* this provider
*/
/**
* Provide a view of this object.
*
* When called by Open MCT, this may include additional arguments
* which are on the path to the object to be viewed; for instance,
* when viewing "A Folder" within "My Items", this method will be
* invoked with "A Folder" (as a domain object) as the first argument,
* and "My Items" as the second argument.
*
* @method view
* @memberof module:openmct.ViewProvider#
* @param {*} object the object to be viewed
* @returns {module:openmct.View} a view of this domain object
*/
/**
* Get metadata associated with this view provider. This may be used
* to populate the user interface with options associated with this
* view provider.
*
* @method metadata
* @memberof module:openmct.ViewProvider#
* @returns {module:openmct.ViewProvider~ViewMetadata} view metadata
*/
/**
* @typedef ViewMetadata
* @memberof module:openmct.ViewProvider~
* @property {string} name the human-readable name of this view
* @property {string} key a machine-readable name for this view
* @property {string} [description] a longer-form description (typically
* a single sentence or short paragraph) of this kind of view
* @property {string} cssclass the CSS class to apply to labels for this
* view (to add icons, for instance)
*/
return ViewRegistry;
});

View File

@@ -55,7 +55,8 @@ requirejs.config({
"screenfull": "bower_components/screenfull/dist/screenfull.min",
"text": "bower_components/text/text",
"uuid": "bower_components/node-uuid/uuid",
"zepto": "bower_components/zepto/zepto.min"
"zepto": "bower_components/zepto/zepto.min",
"lodash": "bower_components/lodash/lodash"
},
"shim": {
@@ -76,6 +77,9 @@ requirejs.config({
},
"zepto": {
"exports": "Zepto"
},
"lodash": {
"exports": "lodash"
}
},

View File

@@ -1,44 +0,0 @@
define(function () {
return function grootPlugin(mct) {
var ROOT_KEY = {
namespace: 'groot',
identifier: 'groot'
};
var GROOT_ROOT = {
name: 'I am groot',
type: 'folder',
composition: [
{
namespace: 'groot',
identifier: 'arms'
},
{
namespace: 'groot',
identifier: 'legs'
},
{
namespace: 'groot',
identifier: 'torso'
}
]
};
var GrootProvider = {
get: function (key) {
if (key.identifier === 'groot') {
return Promise.resolve(GROOT_ROOT);
}
return Promise.resolve({
name: 'Groot\'s ' + key.identifier
});
}
};
mct.Objects.addRoot(ROOT_KEY);
mct.Objects.addProvider('groot', GrootProvider);
return mct;
};
});

View File

@@ -1,59 +0,0 @@
define([
'legacyRegistry',
'./src/controllers/TodoController'
], function (
legacyRegistry,
TodoController
) {
legacyRegistry.register("tutorials/todo", {
"name": "To-do Plugin",
"description": "Allows creating and editing to-do lists.",
"extensions": {
"views": [
{
"key": "example.todo",
"type": "example.todo",
"glyph": "2",
"name": "List",
"templateUrl": "templates/todo.html",
"editable": true,
"toolbar": {
"sections": [
{
"items": [
{
"text": "Add Task",
"glyph": "+",
"method": "addTask",
"control": "button"
}
]
},
{
"items": [
{
"glyph": "Z",
"method": "removeTask",
"control": "button"
}
]
}
]
}
}
],
"controllers": [
{
"key": "TodoController",
"implementation": TodoController,
"depends": [ "$scope", "dialogService" ]
}
],
"stylesheets": [
{
"stylesheetUrl": "css/todo.css"
}
]
}
});
});

View File

@@ -1,29 +0,0 @@
<div ng-controller="TodoController" class="example-todo">
<div class="example-button-group">
<a ng-class="{ selected: checkVisibility(true) }"
ng-click="setVisibility(true)">All</a>
<a ng-class="{ selected: checkVisibility(false, false) }"
ng-click="setVisibility(false, false)">Incomplete</a>
<a ng-class="{ selected: checkVisibility(false, true) }"
ng-click="setVisibility(false, true)">Complete</a>
</div>
<ul>
<li ng-repeat="task in model.tasks"
ng-class="{ 'example-task-completed': task.completed }"
ng-if="showTask(task)">
<input type="checkbox"
ng-checked="task.completed"
ng-click="toggleCompletion($index)">
<span ng-click="selectTask($index)"
ng-class="{ selected: isSelected($index) }"
class="example-task-description">
{{task.description}}
</span>
</li>
</ul>
<div ng-if="model.tasks.length < 1" class="example-message">
There are no tasks to show.
</div>
</div>

View File

@@ -1,97 +0,0 @@
define(function () {
// Form to display when adding new tasks
var NEW_TASK_FORM = {
name: "Add a Task",
sections: [{
rows: [{
name: 'Description',
key: 'description',
control: 'textfield',
required: true
}]
}]
};
function TodoController($scope, dialogService) {
var showAll = true,
showCompleted;
// Persist changes made to a domain object's model
function persist() {
var persistence =
$scope.domainObject.getCapability('persistence');
return persistence && persistence.persist();
}
// Remove a task
function removeTaskAtIndex(taskIndex) {
$scope.domainObject.useCapability('mutation', function (model) {
model.tasks.splice(taskIndex, 1);
});
persist();
}
// Add a task
function addNewTask(task) {
$scope.domainObject.useCapability('mutation', function (model) {
model.tasks.push(task);
});
persist();
}
// Change which tasks are visible
$scope.setVisibility = function (all, completed) {
showAll = all;
showCompleted = completed;
};
// Check if current visibility settings match
$scope.checkVisibility = function (all, completed) {
return showAll ? all : (completed === showCompleted);
};
// Toggle the completion state of a task
$scope.toggleCompletion = function (taskIndex) {
$scope.domainObject.useCapability('mutation', function (model) {
var task = model.tasks[taskIndex];
task.completed = !task.completed;
});
persist();
};
// Check whether a task should be visible
$scope.showTask = function (task) {
return showAll || (showCompleted === !!(task.completed));
};
// Handle selection state in edit mode
if ($scope.selection) {
// Expose the ability to select tasks
$scope.selectTask = function (taskIndex) {
$scope.selection.select({
removeTask: function () {
removeTaskAtIndex(taskIndex);
$scope.selection.deselect();
},
taskIndex: taskIndex
});
};
// Expose a check for current selection state
$scope.isSelected = function (taskIndex) {
return ($scope.selection.get() || {}).taskIndex ===
taskIndex;
};
// Expose a view-level selection proxy
$scope.selection.proxy({
addTask: function () {
dialogService.getUserInput(NEW_TASK_FORM, {})
.then(addNewTask);
}
});
}
}
return TodoController;
});

View File

@@ -0,0 +1,3 @@
<label>Description:
<input type="text" class="description">
</label>

View File

@@ -0,0 +1,5 @@
<li>
<input type="checkbox" class="example-task-checked">
<span class="example-task-description">
</span>
</li>

View File

@@ -0,0 +1,9 @@
<div class="tool-bar btn-bar contents abs">
<a class="s-btn labeled example-add">
<span class="ui-symbol icon">+</span>
<span class="title-label">Add Task</span>
</a>
<a class="s-btn example-remove">
<span class="ui-symbol icon">Z</span>
</a>
</div>

29
tutorials/todo/todo.css Normal file
View File

@@ -0,0 +1,29 @@
.example-todo div.example-button-group {
margin-top: 12px;
margin-bottom: 12px;
}
.example-todo .example-button-group a {
padding: 3px;
margin: 3px;
}
.example-todo .example-button-group a.selected {
border: 1px gray solid;
border-radius: 3px;
background: #444;
}
.example-todo .example-task-completed .example-task-description {
text-decoration: line-through;
opacity: 0.75;
}
.example-todo .example-task-description.selected {
background: #46A;
border-radius: 3px;
}
.example-todo .example-message {
font-style: italic;
}

14
tutorials/todo/todo.html Normal file
View File

@@ -0,0 +1,14 @@
<div class="example-todo">
<div class="example-button-group">
<a class="example-todo-button" data-filter="all">All</a>
<a class="example-todo-button" data-filter="incomplete">Incomplete</a>
<a class="example-todo-button" data-filter="complete">Complete</a>
</div>
<ul class="example-todo-task-list">
</ul>
<div class="example-no-tasks">
There are no tasks to show.
</div>
</div>

View File

@@ -1,4 +1,14 @@
define(function () {
define([
"text!./todo.html",
"text!./todo-task.html",
"text!./todo-toolbar.html",
"text!./todo-dialog.html",
"../../src/api/objects/object-utils",
"zepto"
], function (todoTemplate, taskTemplate, toolbarTemplate, dialogTemplate, utils, $) {
/**
* @param {mct.MCT} mct
*/
return function todoPlugin(mct) {
var todoType = new mct.Type({
metadata: {
@@ -7,12 +17,256 @@ define(function () {
description: "A list of things that need to be done."
},
initialize: function (model) {
model.tasks = [];
model.tasks = [
{ description: "This is a task." }
];
},
creatable: true
});
function TodoView(domainObject) {
this.tasks = domainObject.tasks;
this.filterValue = "all";
this.setTaskStatus = this.setTaskStatus.bind(this);
this.selectTask = this.selectTask.bind(this);
<<<<<<< HEAD
this.mutableObject = mct.Objects.getMutable(domainObject);
this.mutableObject.on('tasks', this.updateTasks.bind(this));
=======
//If anything on object changes, re-render view
this.mutableObject.on("*", this.objectChanged);
};
TodoView.prototype.show = function (container) {
var self = this;
this.destroy();
self.$els = $(todoTemplate);
self.$buttons = {
all: self.$els.find('.example-todo-button-all'),
incomplete: self.$els.find('.example-todo-button-incomplete'),
complete: self.$els.find('.example-todo-button-complete')
};
$(container).empty().append(self.$els);
>>>>>>> origin/api-tutorials
this.$el = $(todoTemplate);
this.$emptyMessage = this.$el.find('.example-no-tasks');
this.$taskList = this.$el.find('.example-todo-task-list');
this.$el.on('click', '[data-filter]', this.updateFilter.bind(this));
this.$el.on('change', 'li', this.setTaskStatus.bind(this));
this.$el.on('click', '.example-task-description', this.selectTask.bind(this));
<<<<<<< HEAD
this.updateSelection = this.updateSelection.bind(this);
mct.selection.on('change', this.updateSelection);
}
TodoView.prototype.show = function (container) {
$(container).empty().append(this.$el);
this.render();
=======
self.initialize();
self.objectChanged(this.domainObject);
mct.selection.on('change', self.render);
>>>>>>> origin/api-tutorials
};
TodoView.prototype.destroy = function () {
this.mutableObject.stopListening();
mct.selection.off('change', this.updateSelection);
};
TodoView.prototype.updateSelection = function (selection) {
if (selection && selection.length) {
this.selection = selection[0].index;
} else {
this.selection = -1;
}
this.render();
};
TodoView.prototype.updateTasks = function (tasks) {
this.tasks = tasks;
this.render();
};
TodoView.prototype.updateFilter = function (e) {
this.filterValue = $(e.target).data('filter');
this.render();
};
TodoView.prototype.setTaskStatus = function (e) {
var $checkbox = $(e.target);
var taskIndex = $checkbox.data('taskIndex');
var completed = !!$checkbox.prop('checked');
this.tasks[taskIndex].completed = completed;
this.mutableObject.set('tasks[' + taskIndex + '].checked', completed);
};
TodoView.prototype.selectTask = function (e) {
var taskIndex = $(e.target).data('taskIndex');
mct.selection.clear();
mct.selection.select({index: taskIndex});
};
TodoView.prototype.getFilteredTasks = function () {
return this.tasks.filter({
all: function () {
return true;
},
incomplete: function (task) {
return !task.completed;
},
complete: function (task) {
return task.completed;
}
}[this.filterValue]);
};
TodoView.prototype.render = function () {
var filteredTasks = this.getFilteredTasks();
this.$emptyMessage.toggle(filteredTasks.length === 0);
this.$taskList.empty();
filteredTasks
.forEach(function (task) {
var $taskEl = $(taskTemplate),
taskIndex = this.tasks.indexOf(task);
$taskEl.find('.example-task-checked')
.prop('checked', task.completed)
.attr('data-task-index', taskIndex);
$taskEl.find('.example-task-description')
.text(task.description)
.toggleClass('selected', taskIndex === this.selection)
.attr('data-task-index', taskIndex);
this.$taskList.append($taskEl);
}, this);
};
function TodoToolbarView(domainObject) {
this.tasks = domainObject.tasks;
this.mutableObject = mct.Objects.getMutable(domainObject);
this.handleSelectionChange = this.handleSelectionChange.bind(this);
this.mutableObject.on('tasks', this.updateTasks.bind(this));
mct.selection.on('change', this.handleSelectionChange);
this.$el = $(toolbarTemplate);
this.$remove = this.$el.find('.example-remove');
this.$el.on('click', '.example-add', this.addTask.bind(this));
this.$el.on('click', '.example-remove', this.removeTask.bind(this));
}
TodoToolbarView.prototype.updateTasks = function (tasks) {
this.tasks = tasks;
};
TodoToolbarView.prototype.addTask = function () {
var $dialog = $(dialogTemplate),
view = {
show: function (container) {
$(container).append($dialog);
},
destroy: function () {}
};
mct.dialog(view, "Add a Task").then(function () {
var description = $dialog.find('input').val();
this.tasks.push({description: description});
this.mutableObject.set('tasks', this.tasks);
}.bind(this));
};
TodoToolbarView.prototype.removeTask = function () {
if (this.selection >= 0) {
this.tasks.splice(this.selection, 1);
this.mutableObject.set('tasks', this.tasks);
mct.selection.clear();
this.render();
}
};
TodoToolbarView.prototype.show = function (container) {
var self = this;
this.destroy();
this.$els = $(toolbarTemplate);
this.render();
$(container).append(this.$els);
};
TodoToolbarView.prototype.render = function () {
var self = this;
var $els = this.$els;
self.mutableObject = mct.Objects.getMutable(this.domainObject);
var $add = $els.find('a.example-add');
var $remove = $els.find('a.example-remove');
$add.on('click', function () {
var $dialog = $(dialogTemplate),
view = {
show: function (container) {
$(container).append($dialog);
},
destroy: function () {}
};
new mct.Dialog(view, "Add a Task").show().then(function () {
var description = $dialog.find('input').val();
var tasks = self.mutableObject.get('tasks');
tasks.push({ description: description });
self.mutableObject.set('tasks', tasks);
});
});
$remove.on('click', function () {
var index = mct.selection.selected()[0].index;
if (index !== undefined) {
var tasks = self.mutableObject.get('tasks').filter(function (t, i) {
return i !== index;
});
self.mutableObject.set("tasks", tasks);
self.mutableObject.set("selected", undefined);
mct.selection.clear();
}
});
self.$remove = $remove;
self.handleSelectionChange();
mct.selection.on('change', self.handleSelectionChange);
};
TodoToolbarView.prototype.handleSelectionChange = function () {
var selected = mct.selection.selected();
if (this.$remove) {
this.$remove.toggle(selected.length > 0);
}
this.render();
};
TodoToolbarView.prototype.destroy = function () {
mct.selection.off('change', this.handleSelectionChange);
this.mutableObject.stopListening();
};
mct.type('example.todo', todoType);
mct.view(mct.regions.main, {
view: function (domainObject) {
return new TodoView(domainObject);
},
canView: todoType.check.bind(todoType)
});
mct.view(mct.regions.toolbar, {
view: function (domainObject) {
return new TodoToolbarView(domainObject);
},
canView: todoType.check.bind(todoType)
});
return mct;
};