Compare commits
129 Commits
open933_mo
...
api-1111
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ce9bd969a | ||
|
|
8cafd2da7e | ||
|
|
6264ab75f3 | ||
|
|
7a5cad20ec | ||
|
|
4de069b393 | ||
|
|
70abd5c1f9 | ||
|
|
2a3a61da86 | ||
|
|
018bd022cc | ||
|
|
4739b36bc3 | ||
|
|
c9b1035a6d | ||
|
|
6768328475 | ||
|
|
60c179eac3 | ||
|
|
a20e8d69b5 | ||
|
|
1abcb248fe | ||
|
|
a8151f5f22 | ||
|
|
cdf21f3763 | ||
|
|
341bceb4e2 | ||
|
|
0470a02272 | ||
|
|
e3dc26c130 | ||
|
|
96c3d1cac2 | ||
|
|
2af778145d | ||
|
|
5743eeb33a | ||
|
|
f06f714bdc | ||
|
|
d592bd1035 | ||
|
|
b5f62541ce | ||
|
|
33ced4bccf | ||
|
|
e37510dbab | ||
|
|
f27c41014d | ||
|
|
bd796f2beb | ||
|
|
bcc32c76d0 | ||
|
|
ff2ec6690a | ||
|
|
1e0fb3611d | ||
|
|
1d4f36a7d9 | ||
|
|
0f96fbdd62 | ||
|
|
e05fb57fe4 | ||
|
|
185cdcab08 | ||
|
|
50ccad5aaa | ||
|
|
6a23df9454 | ||
|
|
ab5b1d3754 | ||
|
|
b309f26b56 | ||
|
|
b4dc50295c | ||
|
|
382dde300a | ||
|
|
02aa08a3ef | ||
|
|
c95d9c7956 | ||
|
|
b1b8df4d87 | ||
|
|
bd3c6665fb | ||
|
|
10e90519c0 | ||
|
|
d341a8be97 | ||
|
|
8c439d8109 | ||
|
|
9c88b7ce1d | ||
|
|
2463e4d59f | ||
|
|
d73c505bea | ||
|
|
831ecc59d9 | ||
|
|
1de26d3c5d | ||
|
|
11409ce509 | ||
|
|
93872ce074 | ||
|
|
8861644f2d | ||
|
|
d4948f771b | ||
|
|
8295a0bed1 | ||
|
|
0656a298da | ||
|
|
fe2ce91d50 | ||
|
|
14f30b2489 | ||
|
|
62d90a8114 | ||
|
|
87682607a5 | ||
|
|
7bf265b478 | ||
|
|
1d31fe8d02 | ||
|
|
bfdbc71e40 | ||
|
|
1147f3aa47 | ||
|
|
719f9f45e8 | ||
|
|
95ef70a24c | ||
|
|
d5aa998b4c | ||
|
|
7890fcae69 | ||
|
|
18843cee48 | ||
|
|
1879c122c7 | ||
|
|
d7ddb96c4e | ||
|
|
bccd018d97 | ||
|
|
b55668426d | ||
|
|
5b656faa9d | ||
|
|
8d2c489fa9 | ||
|
|
4366b0870d | ||
|
|
47a543beb7 | ||
|
|
06f87c1472 | ||
|
|
c9c41cdcc8 | ||
|
|
14a56ea17e | ||
|
|
b2e7db71cc | ||
|
|
d51e6bfd92 | ||
|
|
d475d767d5 | ||
|
|
a63e053399 | ||
|
|
370b515c23 | ||
|
|
4a50f325cb | ||
|
|
dbe6a4efc1 | ||
|
|
13920d8802 | ||
|
|
b6a8c514aa | ||
|
|
e4a4704baa | ||
|
|
be0029e59a | ||
|
|
9cb273ef0a | ||
|
|
eec9b1cf4c | ||
|
|
1f96e84542 | ||
|
|
c289a27305 | ||
|
|
c944080790 | ||
|
|
96316de6e4 | ||
|
|
2240a87ddc | ||
|
|
d891affe48 | ||
|
|
21a618d1ce | ||
|
|
5de7a96ccc | ||
|
|
09a833f524 | ||
|
|
580a4e52b5 | ||
|
|
9c4e17bfab | ||
|
|
d3e5d95d6b | ||
|
|
c70793ac2d | ||
|
|
a6ef1d3423 | ||
|
|
4ca2f51d5e | ||
|
|
86ac80ddbd | ||
|
|
0525ba6b0b | ||
|
|
a79e958ffc | ||
|
|
03cb0ccb57 | ||
|
|
7205faa6bb | ||
|
|
136f2ae785 | ||
|
|
a07e2fb8e5 | ||
|
|
55b531bdeb | ||
|
|
7ece5897e8 | ||
|
|
a29c7a6eab | ||
|
|
c4fec1af6a | ||
|
|
a6996df3df | ||
|
|
0c660238f2 | ||
|
|
b73b824e55 | ||
|
|
1954d98628 | ||
|
|
7aa034ce23 | ||
|
|
385dc5d298 |
114
API.md
Normal file
114
API.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# 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 standard browser loading; it's easy to use
|
||||
in your project.
|
||||
|
||||
## 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 a domain object. 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.
|
||||
|
||||
## The API
|
||||
|
||||
### `MCT.Type(options)`
|
||||
Status: First Draft
|
||||
|
||||
Returns a `typeInstance`. `options` is an object supporting the following properties:
|
||||
|
||||
* `metadata`: `object` defining metadata used in displaying the object; has the following properties:
|
||||
* `label`: `string`, the human-readible name of the type. used in menus and inspector.
|
||||
* `glyph`: `string`, the name of the icon to display for this type, used in labels.
|
||||
* `description`: `string`, a human readible description of the object and what it is for.
|
||||
* `initialize`: `function` which initializes new instances of this type. it is called with an object, should add any default properties to that object.
|
||||
* `creatable`: `boolean`, if true, this object will be visible in the create menu.
|
||||
* `form`: `Array` an array of form fields, as defined... somewhere! Generates a property sheet that is visible while editing this object.
|
||||
|
||||
### `MCT.type(typeKey, typeInstance)`
|
||||
Status: First Draft
|
||||
|
||||
Register a `typeInstance` with a given Type `key` (a `string`). There can only be one `typeInstance` registered per type `key`. typeInstances must be registered before they can be utilized.
|
||||
|
||||
### `MCT.Objects`
|
||||
Status: First Draft
|
||||
|
||||
Allows you to register object providers, which allows you to integrate domain objects from various different sources. Also implements methods for mutation and persistence of objects. See [Object API](src/api/objects/README.md) for more details.
|
||||
|
||||
### `MCT.Composition`
|
||||
Status: First Draft
|
||||
|
||||
Objects can contain other objects, and the Composition API allows you to fetch the composition of any given domain object, or implement custom methods for defining composition as necessary.
|
||||
|
||||
### `MCT.view(region, definition)`
|
||||
Status: First Draft
|
||||
|
||||
Register a view factory for a specific region. View factories receive an instance of a domain object and return a `View` for that object, or return undefined if they do not know how to generate a view for that object.
|
||||
|
||||
* `ViewDefinition`: an object with the following properties:
|
||||
* `canView(domainObject)`: should return truthy if the view is valid for a given domain object, falsy if it is not capable of generating a view for that object.
|
||||
* `view(domainObject)`: should instantate and return a `View` for the given object.
|
||||
* `metadata()`: a function that returns metadata about this view. Optional.
|
||||
* `View`: an object containing a number of lifecycle methods:
|
||||
* `view.show(container)`: instantiate a view (a set of dom elements) and attach it to the container.
|
||||
* `view.destroy(container)`: remove any listeners and expect your dom elements to be destroyed.
|
||||
|
||||
For a basic introduction to views & types, check out these tutorials:
|
||||
|
||||
* [custom-view](custom-view.html) -- Implementing a custom view with vanilla javascript.
|
||||
* [custom-view-react](custom-view-react.html) -- Implementing a custom view with React.
|
||||
|
||||
### `MCT.conductor`
|
||||
Status: First Draft
|
||||
|
||||
The time conductor is an API that facilitates time synchronization across multiple components. Components that would like to be "time aware" may attach listeners to the time conductor API to allow them to remain synchronized with other components. For more information ont he time conductor API, please look at the API draft here: https://github.com/nasa/openmct/blob/66220b89ca568075f107505ba414de9457dc0427/platform/features/conductor-redux/src/README.md
|
||||
|
||||
### `MCT.selection`
|
||||
Status: First Draft
|
||||
|
||||
Tracks the application's selection state (which elements of a view has a user selected?)
|
||||
|
||||
One or more JavaScript objects may be selected at any given time. User code is responsible for any necessary type-checking.
|
||||
|
||||
The following methods are exposed from this object:
|
||||
|
||||
* `select(value)`: Add `value` to the current selection.
|
||||
* `deselect(value)`: Remove `value` from the current selection.
|
||||
* `selected()`: Get array of all selected objects.
|
||||
* `clear()`: Deselect all selected objects.
|
||||
|
||||
MCT.selection is an EventEmitter; a `change` event is emitted whenever the selection changes.
|
||||
|
||||
### `MCT.systems`
|
||||
Status: Not Implemented, Needs to be ported from old system.
|
||||
|
||||
A registry for different time system definitions. Based upon the previous time format system which utilized the "formats" extension category.
|
||||
|
||||
### `MCT.run([container])`
|
||||
Status: Stable Draft
|
||||
|
||||
Run the MCT application, loading the application into the `container`, a DOM element. If a container is not specified, the application is injected into the body of the page.
|
||||
|
||||
### `MCT.install(plugin)`
|
||||
Status: Stable Draft
|
||||
|
||||
Install a plugin in MCT. Must be called before calling `run`. Plugins are functions which are invoked with the `MCT` instance as their first argument, and are expected to use the MCT public API to add functionality.
|
||||
|
||||
For an example of writing a plugin, check out [plugin-example.html](plugin-example.html)
|
||||
|
||||
### `MCT.setAssetPath(path)`
|
||||
|
||||
Sets the path (absolute or relative) at which the Open MCT static files are being hosted. The default value is '.'.
|
||||
|
||||
Note that this API is transitional and will be removed in a future version.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Open MCT [](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# Open MCT
|
||||
|
||||
Open MCT is a web-based platform for mission operations user interface
|
||||
software.
|
||||
@@ -7,7 +7,7 @@ software.
|
||||
|
||||
A bundle is a group of software components (including source code, declared
|
||||
as AMD modules, as well as resources such as images and HTML templates)
|
||||
that is intended to be added or removed as a single unit. A plug-in for
|
||||
that are intended to be added or removed as a single unit. A plug-in for
|
||||
Open MCT will be expressed as a bundle; platform components are also
|
||||
expressed as bundles.
|
||||
|
||||
@@ -133,6 +133,6 @@ documentation, may presume an understanding of these terms.
|
||||
it, and it is thereafter considered the _navigated_ object (until the
|
||||
user makes another such choice.)
|
||||
* _space_: A name used to identify a persistence store. Interactions with
|
||||
persistence will generally involve a `space` parameter in some form, to
|
||||
persistence with generally involve a `space` parameter in some form, to
|
||||
distinguish multiple persistence stores from one another (for cases
|
||||
where there are multiple valid persistence locations available.)
|
||||
|
||||
8
app.js
8
app.js
@@ -75,8 +75,6 @@
|
||||
// Expose everything else as static files
|
||||
app.use(express['static'](options.directory));
|
||||
|
||||
// Finally, open the HTTP server and log the instance to the console
|
||||
app.listen(options.port, function() {
|
||||
console.log('Open MCT application running at localhost:' + options.port)
|
||||
});
|
||||
}());
|
||||
// Finally, open the HTTP server
|
||||
app.listen(options.port);
|
||||
}());
|
||||
@@ -20,6 +20,7 @@
|
||||
"FileSaver.js": "^0.0.2",
|
||||
"zepto": "^1.1.6",
|
||||
"eventemitter3": "^1.2.0",
|
||||
"d3": "~4.1.0"
|
||||
"lodash": "3.10.1",
|
||||
"almond": "~0.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
13
build/jsdoc/plugins/mct-only.js
Normal file
13
build/jsdoc/plugins/mct-only.js
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
handlers: {
|
||||
processingComplete: function (e) {
|
||||
e.doclets.forEach(function (doclet) {
|
||||
var memberof = doclet.memberof || "";
|
||||
var longname = doclet.longname || "";
|
||||
|
||||
doclet.ignore = longname !== 'module:openmct' &&
|
||||
memberof.indexOf('module:openmct') !== 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
65
composition-test.html
Normal file
65
composition-test.html
Normal 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
144
custom-view-react.html
Normal 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
160
custom-view.html
Normal 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>
|
||||
@@ -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": [
|
||||
|
||||
68
gulpfile.js
68
gulpfile.js
@@ -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,35 @@ 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('api', function () {
|
||||
var jsdoc2md = require('gulp-jsdoc-to-markdown');
|
||||
var concat = require('gulp-concat');
|
||||
var markdown = require('gulp-markdown');
|
||||
return gulp.src('src/**/*.js')
|
||||
.pipe(concat('api.md'))
|
||||
.pipe(jsdoc2md(require('./jsdoc.json')))
|
||||
.pipe(markdown())
|
||||
.pipe(gulp.dest(paths.dist));
|
||||
});
|
||||
|
||||
gulp.task('api-watch', function () {
|
||||
return gulp.watch('src/**/*.js', ['api']);
|
||||
});
|
||||
|
||||
gulp.task('serve', function () {
|
||||
@@ -143,9 +165,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' ]);
|
||||
|
||||
|
||||
@@ -31,10 +31,14 @@
|
||||
<script type="text/javascript">
|
||||
require(['main'], function (mct) {
|
||||
require([
|
||||
'./tutorials/todo/todo',
|
||||
'./example/imagery/bundle',
|
||||
'./example/eventGenerator/bundle',
|
||||
'./example/generator/bundle'
|
||||
], mct.run.bind(mct));
|
||||
], function (todoPlugin) {
|
||||
mct.install(todoPlugin);
|
||||
mct.run();
|
||||
})
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="platform/commonUI/general/res/css/startup-base.css">
|
||||
@@ -48,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>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"source": {
|
||||
"include": [
|
||||
"platform/"
|
||||
"src/"
|
||||
],
|
||||
"includePattern": "platform/.+\\.js$",
|
||||
"includePattern": "src/.+\\.js$",
|
||||
"excludePattern": ".+\\Spec\\.js$|lib/.+"
|
||||
},
|
||||
"plugins": [
|
||||
"plugins/markdown"
|
||||
"plugins/markdown",
|
||||
"build/jsdoc/plugins/mct-only"
|
||||
]
|
||||
}
|
||||
|
||||
66
main.js
66
main.js
@@ -36,7 +36,7 @@ requirejs.config({
|
||||
"text": "bower_components/text/text",
|
||||
"uuid": "bower_components/node-uuid/uuid",
|
||||
"zepto": "bower_components/zepto/zepto.min",
|
||||
"d3": "bower_components/d3/d3.min"
|
||||
"lodash": "bower_components/lodash/lodash"
|
||||
},
|
||||
"shim": {
|
||||
"angular": {
|
||||
@@ -57,57 +57,31 @@ requirejs.config({
|
||||
"zepto": {
|
||||
"exports": "Zepto"
|
||||
},
|
||||
"d3": {
|
||||
"exports": "d3"
|
||||
"lodash": {
|
||||
"exports": "lodash"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
define([
|
||||
'./platform/framework/src/Main',
|
||||
'legacyRegistry',
|
||||
'./src/defaultRegistry',
|
||||
'./src/MCT'
|
||||
], function (Main, defaultRegistry, MCT) {
|
||||
var mct = new 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/conductor-v2/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',
|
||||
'./example/msl/bundle'
|
||||
], function (Main, legacyRegistry) {
|
||||
return {
|
||||
legacyRegistry: legacyRegistry,
|
||||
run: function () {
|
||||
return new Main().run(legacyRegistry);
|
||||
}
|
||||
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(defaultRegistry);
|
||||
});
|
||||
|
||||
return mct;
|
||||
});
|
||||
|
||||
64
object-provider.html
Normal file
64
object-provider.html
Normal 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>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "0.11.0-SNAPSHOT",
|
||||
"version": "0.10.2-SNAPSHOT",
|
||||
"description": "The Open MCT core platform",
|
||||
"dependencies": {
|
||||
"express": "^4.13.1",
|
||||
@@ -12,8 +12,11 @@
|
||||
"git-rev-sync": "^1.4.0",
|
||||
"glob": ">= 3.0.0",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-jscs": "^3.0.2",
|
||||
"gulp-jsdoc-to-markdown": "^1.2.2",
|
||||
"gulp-jshint": "^2.0.0",
|
||||
"gulp-markdown": "^1.2.0",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-replace-task": "^0.11.0",
|
||||
"gulp-requirejs-optimize": "^0.3.1",
|
||||
@@ -47,7 +50,7 @@
|
||||
"test": "karma start --single-run",
|
||||
"jshint": "jshint platform example",
|
||||
"watch": "karma start",
|
||||
"jsdoc": "jsdoc -c jsdoc.json -r -d target/docs/api",
|
||||
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d target/docs/api",
|
||||
"otherdoc": "node docs/gendocs.js --in docs/src --out target/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
|
||||
"docs": "npm run jsdoc ; npm run otherdoc",
|
||||
"prepublish": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
|
||||
|
||||
@@ -27,7 +27,6 @@ define([
|
||||
"./src/MenuArrowController",
|
||||
"./src/navigation/NavigationService",
|
||||
"./src/navigation/NavigateAction",
|
||||
"./src/navigation/OrphanNavigationHandler",
|
||||
"./src/windowing/NewTabAction",
|
||||
"./src/windowing/FullscreenAction",
|
||||
"./src/windowing/WindowTitler",
|
||||
@@ -40,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,
|
||||
@@ -48,7 +48,6 @@ define([
|
||||
MenuArrowController,
|
||||
NavigationService,
|
||||
NavigateAction,
|
||||
OrphanNavigationHandler,
|
||||
NewTabAction,
|
||||
FullscreenAction,
|
||||
WindowTitler,
|
||||
@@ -61,6 +60,7 @@ define([
|
||||
itemsTemplate,
|
||||
objectPropertiesTemplate,
|
||||
inspectorRegionTemplate,
|
||||
viewObjectTemplate,
|
||||
legacyRegistry
|
||||
) {
|
||||
|
||||
@@ -93,9 +93,11 @@ define([
|
||||
"$scope",
|
||||
"$route",
|
||||
"$location",
|
||||
"$window",
|
||||
"objectService",
|
||||
"navigationService",
|
||||
"urlService",
|
||||
"policyService",
|
||||
"DEFAULT_PATH"
|
||||
]
|
||||
},
|
||||
@@ -129,7 +131,7 @@ define([
|
||||
"representations": [
|
||||
{
|
||||
"key": "view-object",
|
||||
"templateUrl": "templates/view-object.html"
|
||||
"template": viewObjectTemplate
|
||||
},
|
||||
{
|
||||
"key": "browse-object",
|
||||
@@ -199,9 +201,7 @@ define([
|
||||
"implementation": NavigateAction,
|
||||
"depends": [
|
||||
"navigationService",
|
||||
"$q",
|
||||
"policyService",
|
||||
"$window"
|
||||
"$q"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -255,14 +255,6 @@ define([
|
||||
"$rootScope",
|
||||
"$document"
|
||||
]
|
||||
},
|
||||
{
|
||||
"implementation": OrphanNavigationHandler,
|
||||
"depends": [
|
||||
"throttle",
|
||||
"topic",
|
||||
"navigationService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
<div class="holder l-flex-col flex-elem grows l-object-wrapper l-controls-visible l-time-controller-visible">
|
||||
<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">
|
||||
@@ -59,9 +59,4 @@
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
<!-- put time conductor in here? -->
|
||||
<mct-representation mct-object="domainObject"
|
||||
key="'time-conductor'"
|
||||
class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder">
|
||||
</mct-representation>
|
||||
</div>
|
||||
|
||||
@@ -44,9 +44,11 @@ define(
|
||||
$scope,
|
||||
$route,
|
||||
$location,
|
||||
$window,
|
||||
objectService,
|
||||
navigationService,
|
||||
urlService,
|
||||
policyService,
|
||||
defaultPath
|
||||
) {
|
||||
var path = [ROOT_ID].concat(
|
||||
@@ -73,10 +75,25 @@ define(
|
||||
|
||||
}
|
||||
|
||||
function setScopeObjects(domainObject, navigationAllowed) {
|
||||
// Callback for updating the in-scope reference to the object
|
||||
// that is currently navigated-to.
|
||||
function setNavigation(domainObject) {
|
||||
var navigationAllowed = true;
|
||||
|
||||
if (domainObject === $scope.navigatedObject) {
|
||||
//do nothing;
|
||||
return;
|
||||
}
|
||||
|
||||
policyService.allow("navigation", $scope.navigatedObject, domainObject, function (message) {
|
||||
navigationAllowed = $window.confirm(message + "\r\n\r\n" +
|
||||
" Are you sure you want to continue?");
|
||||
});
|
||||
|
||||
if (navigationAllowed) {
|
||||
$scope.navigatedObject = domainObject;
|
||||
$scope.treeModel.selectedObject = domainObject;
|
||||
navigationService.setNavigation(domainObject);
|
||||
updateRoute(domainObject);
|
||||
} else {
|
||||
//If navigation was unsuccessful (ie. blocked), reset
|
||||
@@ -86,20 +103,6 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
// Callback for updating the in-scope reference to the object
|
||||
// that is currently navigated-to.
|
||||
function setNavigation(domainObject) {
|
||||
if (domainObject === $scope.navigatedObject) {
|
||||
//do nothing;
|
||||
return;
|
||||
}
|
||||
if (domainObject) {
|
||||
domainObject.getCapability("action").perform("navigate").then(setScopeObjects.bind(undefined, domainObject));
|
||||
} else {
|
||||
setScopeObjects(domainObject, true);
|
||||
}
|
||||
}
|
||||
|
||||
function navigateTo(domainObject) {
|
||||
|
||||
// Check if an object has been navigated-to already...
|
||||
|
||||
@@ -33,12 +33,10 @@ define(
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
*/
|
||||
function NavigateAction(navigationService, $q, policyService, $window, context) {
|
||||
function NavigateAction(navigationService, $q, context) {
|
||||
this.domainObject = context.domainObject;
|
||||
this.$q = $q;
|
||||
this.navigationService = navigationService;
|
||||
this.policyService = policyService;
|
||||
this.$window = $window;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,20 +45,9 @@ define(
|
||||
* navigation has been updated
|
||||
*/
|
||||
NavigateAction.prototype.perform = function () {
|
||||
var self = this,
|
||||
navigationAllowed = true;
|
||||
|
||||
function allow() {
|
||||
self.policyService.allow("navigation", self.navigationService.getNavigation(), self.domainObject, function (message) {
|
||||
navigationAllowed = self.$window.confirm(message + "\r\n\r\n" +
|
||||
" Are you sure you want to continue?");
|
||||
});
|
||||
return navigationAllowed;
|
||||
}
|
||||
|
||||
// Set navigation, and wrap like a promise
|
||||
return this.$q.when(
|
||||
allow() && this.navigationService.setNavigation(this.domainObject)
|
||||
this.navigationService.setNavigation(this.domainObject)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([], function () {
|
||||
|
||||
/**
|
||||
* Navigates away from orphan objects whenever they are detected.
|
||||
*
|
||||
* An orphan object is an object whose apparent parent does not
|
||||
* actually contain it. This may occur in certain circumstances, such
|
||||
* as when persistence succeeds for a newly-created object but fails
|
||||
* for its parent.
|
||||
*
|
||||
* @param throttle the `throttle` service
|
||||
* @param topic the `topic` service
|
||||
* @param navigationService the `navigationService`
|
||||
* @constructor
|
||||
*/
|
||||
function OrphanNavigationHandler(throttle, topic, navigationService) {
|
||||
var throttledCheckNavigation;
|
||||
|
||||
function getParent(domainObject) {
|
||||
var context = domainObject.getCapability('context');
|
||||
return context.getParent();
|
||||
}
|
||||
|
||||
function isOrphan(domainObject) {
|
||||
var parent = getParent(domainObject),
|
||||
composition = parent.getModel().composition,
|
||||
id = domainObject.getId();
|
||||
return !composition || (composition.indexOf(id) === -1);
|
||||
}
|
||||
|
||||
function navigateToParent(domainObject) {
|
||||
var parent = getParent(domainObject);
|
||||
return parent.getCapability('action').perform('navigate');
|
||||
}
|
||||
|
||||
function checkNavigation() {
|
||||
var navigatedObject = navigationService.getNavigation();
|
||||
if (navigatedObject.hasCapability('context') &&
|
||||
isOrphan(navigatedObject)) {
|
||||
if (!navigatedObject.getCapability('editor').isEditContextRoot()) {
|
||||
navigateToParent(navigatedObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throttledCheckNavigation = throttle(checkNavigation);
|
||||
|
||||
navigationService.addListener(throttledCheckNavigation);
|
||||
topic('mutation').listen(throttledCheckNavigation);
|
||||
}
|
||||
|
||||
return OrphanNavigationHandler;
|
||||
});
|
||||
@@ -37,8 +37,9 @@ define(
|
||||
mockUrlService,
|
||||
mockDomainObject,
|
||||
mockNextObject,
|
||||
mockWindow,
|
||||
mockPolicyService,
|
||||
testDefaultRoot,
|
||||
mockActionCapability,
|
||||
controller;
|
||||
|
||||
function mockPromise(value) {
|
||||
@@ -54,14 +55,25 @@ define(
|
||||
mockScope,
|
||||
mockRoute,
|
||||
mockLocation,
|
||||
mockWindow,
|
||||
mockObjectService,
|
||||
mockNavigationService,
|
||||
mockUrlService,
|
||||
mockPolicyService,
|
||||
testDefaultRoot
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockWindow = jasmine.createSpyObj('$window', [
|
||||
"confirm"
|
||||
]);
|
||||
mockWindow.confirm.andReturn(true);
|
||||
|
||||
mockPolicyService = jasmine.createSpyObj('policyService', [
|
||||
'allow'
|
||||
]);
|
||||
|
||||
testDefaultRoot = "some-root-level-domain-object";
|
||||
|
||||
mockScope = jasmine.createSpyObj(
|
||||
@@ -116,8 +128,6 @@ define(
|
||||
mockNextObject.getId.andReturn("next");
|
||||
mockDomainObject.getId.andReturn(testDefaultRoot);
|
||||
|
||||
mockActionCapability = jasmine.createSpyObj('actionCapability', ['perform']);
|
||||
|
||||
instantiateController();
|
||||
});
|
||||
|
||||
@@ -201,13 +211,8 @@ define(
|
||||
mockContext.getPath.andReturn(
|
||||
[mockRootObject, mockDomainObject, mockNextObject]
|
||||
);
|
||||
|
||||
//Return true from navigate action
|
||||
mockActionCapability.perform.andReturn(mockPromise(true));
|
||||
|
||||
mockNextObject.getCapability.andCallFake(function (c) {
|
||||
return (c === 'context' && mockContext) ||
|
||||
(c === 'action' && mockActionCapability);
|
||||
return c === 'context' && mockContext;
|
||||
});
|
||||
mockScope.$on.andReturn(mockUnlisten);
|
||||
// Provide a navigation change
|
||||
@@ -220,7 +225,6 @@ define(
|
||||
mockLocation.path.andReturn("/browse/");
|
||||
|
||||
mockNavigationService.setNavigation.andReturn(true);
|
||||
mockActionCapability.perform.andReturn(mockPromise(true));
|
||||
|
||||
// Exercise the Angular workaround
|
||||
mockNavigationService.addListener.mostRecentCall.args[0]();
|
||||
@@ -239,9 +243,6 @@ define(
|
||||
mockScope.navigatedObject = mockDomainObject;
|
||||
mockNavigationService.setNavigation.andReturn(true);
|
||||
|
||||
mockActionCapability.perform.andReturn(mockPromise(true));
|
||||
mockNextObject.getCapability.andReturn(mockActionCapability);
|
||||
|
||||
//Simulate a change in selected tree object
|
||||
mockScope.treeModel = {selectedObject: mockDomainObject};
|
||||
mockScope.$watch.mostRecentCall.args[1](mockNextObject);
|
||||
@@ -253,10 +254,11 @@ define(
|
||||
it("after failed navigation event resets the selected tree" +
|
||||
" object", function () {
|
||||
mockScope.navigatedObject = mockDomainObject;
|
||||
|
||||
//Return false from navigation action
|
||||
mockActionCapability.perform.andReturn(mockPromise(false));
|
||||
mockNextObject.getCapability.andReturn(mockActionCapability);
|
||||
mockWindow.confirm.andReturn(false);
|
||||
mockPolicyService.allow.andCallFake(function (category, object, context, callback) {
|
||||
callback("unsaved changes");
|
||||
return false;
|
||||
});
|
||||
|
||||
//Simulate a change in selected tree object
|
||||
mockScope.treeModel = {selectedObject: mockDomainObject};
|
||||
|
||||
@@ -31,8 +31,6 @@ define(
|
||||
var mockNavigationService,
|
||||
mockQ,
|
||||
mockDomainObject,
|
||||
mockPolicyService,
|
||||
mockWindow,
|
||||
action;
|
||||
|
||||
function mockPromise(value) {
|
||||
@@ -46,70 +44,25 @@ define(
|
||||
beforeEach(function () {
|
||||
mockNavigationService = jasmine.createSpyObj(
|
||||
"navigationService",
|
||||
[
|
||||
"setNavigation",
|
||||
"getNavigation"
|
||||
]
|
||||
["setNavigation"]
|
||||
);
|
||||
mockNavigationService.getNavigation.andReturn({});
|
||||
mockQ = { when: mockPromise };
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getModel", "getCapability"]
|
||||
);
|
||||
|
||||
mockPolicyService = jasmine.createSpyObj("policyService",
|
||||
[
|
||||
"allow"
|
||||
]);
|
||||
mockWindow = jasmine.createSpyObj("$window",
|
||||
[
|
||||
"confirm"
|
||||
]);
|
||||
|
||||
action = new NavigateAction(
|
||||
mockNavigationService,
|
||||
mockQ,
|
||||
mockPolicyService,
|
||||
mockWindow,
|
||||
{ domainObject: mockDomainObject }
|
||||
);
|
||||
});
|
||||
|
||||
it("invokes the policy service to determine if navigation" +
|
||||
" allowed", function () {
|
||||
it("invokes the navigate service when performed", function () {
|
||||
action.perform();
|
||||
expect(mockPolicyService.allow)
|
||||
.toHaveBeenCalledWith("navigation", jasmine.any(Object), jasmine.any(Object), jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("prompts user if policy rejection", function () {
|
||||
action.perform();
|
||||
expect(mockPolicyService.allow).toHaveBeenCalled();
|
||||
mockPolicyService.allow.mostRecentCall.args[3]();
|
||||
expect(mockWindow.confirm).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("shows a prompt", function () {
|
||||
beforeEach(function () {
|
||||
// Ensure the allow callback is called synchronously
|
||||
mockPolicyService.allow.andCallFake(function () {
|
||||
return arguments[3]();
|
||||
});
|
||||
});
|
||||
it("does not navigate on prompt rejection", function () {
|
||||
mockWindow.confirm.andReturn(false);
|
||||
action.perform();
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does navigate on prompt acceptance", function () {
|
||||
mockWindow.confirm.andReturn(true);
|
||||
action.perform();
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.toHaveBeenCalledWith(mockDomainObject);
|
||||
});
|
||||
|
||||
it("is only applicable when a domain object is in context", function () {
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'../../src/navigation/OrphanNavigationHandler'
|
||||
], function (OrphanNavigationHandler) {
|
||||
describe("OrphanNavigationHandler", function () {
|
||||
var mockTopic,
|
||||
mockThrottle,
|
||||
mockMutationTopic,
|
||||
mockNavigationService,
|
||||
mockDomainObject,
|
||||
mockParentObject,
|
||||
mockContext,
|
||||
mockActionCapability,
|
||||
mockEditor,
|
||||
testParentModel,
|
||||
testId,
|
||||
mockThrottledFns;
|
||||
|
||||
beforeEach(function () {
|
||||
testId = 'some-identifier';
|
||||
|
||||
mockThrottledFns = [];
|
||||
testParentModel = {};
|
||||
|
||||
mockTopic = jasmine.createSpy('topic');
|
||||
mockThrottle = jasmine.createSpy('throttle');
|
||||
mockNavigationService = jasmine.createSpyObj('navigationService', [
|
||||
'getNavigation',
|
||||
'addListener'
|
||||
]);
|
||||
mockMutationTopic = jasmine.createSpyObj('mutationTopic', [
|
||||
'listen'
|
||||
]);
|
||||
mockDomainObject = jasmine.createSpyObj('domainObject', [
|
||||
'getId',
|
||||
'getCapability',
|
||||
'getModel',
|
||||
'hasCapability'
|
||||
]);
|
||||
mockParentObject = jasmine.createSpyObj('domainObject', [
|
||||
'getId',
|
||||
'getCapability',
|
||||
'getModel',
|
||||
'hasCapability'
|
||||
]);
|
||||
mockContext = jasmine.createSpyObj('context', ['getParent']);
|
||||
mockActionCapability = jasmine.createSpyObj('action', ['perform']);
|
||||
mockEditor = jasmine.createSpyObj('editor', ['isEditContextRoot']);
|
||||
|
||||
mockThrottle.andCallFake(function (fn) {
|
||||
var mockThrottledFn =
|
||||
jasmine.createSpy('throttled-' + mockThrottledFns.length);
|
||||
mockThrottledFn.andCallFake(fn);
|
||||
mockThrottledFns.push(mockThrottledFn);
|
||||
return mockThrottledFn;
|
||||
});
|
||||
mockTopic.andCallFake(function (k) {
|
||||
return k === 'mutation' && mockMutationTopic;
|
||||
});
|
||||
mockDomainObject.getId.andReturn(testId);
|
||||
mockDomainObject.getCapability.andCallFake(function (c) {
|
||||
return {
|
||||
context: mockContext,
|
||||
editor: mockEditor
|
||||
}[c];
|
||||
});
|
||||
mockDomainObject.hasCapability.andCallFake(function (c) {
|
||||
return !!mockDomainObject.getCapability(c);
|
||||
});
|
||||
mockParentObject.getModel.andReturn(testParentModel);
|
||||
mockParentObject.getCapability.andCallFake(function (c) {
|
||||
return {
|
||||
action: mockActionCapability
|
||||
}[c];
|
||||
});
|
||||
mockContext.getParent.andReturn(mockParentObject);
|
||||
mockNavigationService.getNavigation.andReturn(mockDomainObject);
|
||||
mockEditor.isEditContextRoot.andReturn(false);
|
||||
|
||||
return new OrphanNavigationHandler(
|
||||
mockThrottle,
|
||||
mockTopic,
|
||||
mockNavigationService
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it("listens for mutation with a throttled function", function () {
|
||||
expect(mockMutationTopic.listen)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
expect(mockThrottledFns.indexOf(
|
||||
mockMutationTopic.listen.mostRecentCall.args[0]
|
||||
)).not.toEqual(-1);
|
||||
});
|
||||
|
||||
it("listens for navigation changes with a throttled function", function () {
|
||||
expect(mockNavigationService.addListener)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
expect(mockThrottledFns.indexOf(
|
||||
mockNavigationService.addListener.mostRecentCall.args[0]
|
||||
)).not.toEqual(-1);
|
||||
});
|
||||
|
||||
[false, true].forEach(function (isOrphan) {
|
||||
var prefix = isOrphan ? "" : "non-";
|
||||
describe("for " + prefix + "orphan objects", function () {
|
||||
beforeEach(function () {
|
||||
testParentModel.composition = isOrphan ? [] : [testId];
|
||||
});
|
||||
|
||||
[false, true].forEach(function (isEditRoot) {
|
||||
var caseName = isEditRoot ?
|
||||
"that are being edited" : "that are not being edited";
|
||||
|
||||
function itNavigatesAsExpected() {
|
||||
if (isOrphan && !isEditRoot) {
|
||||
it("navigates to the parent", function () {
|
||||
expect(mockActionCapability.perform)
|
||||
.toHaveBeenCalledWith('navigate');
|
||||
});
|
||||
} else {
|
||||
it("does nothing", function () {
|
||||
expect(mockActionCapability.perform)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
describe(caseName, function () {
|
||||
beforeEach(function () {
|
||||
mockEditor.isEditContextRoot.andReturn(isEditRoot);
|
||||
});
|
||||
|
||||
describe("when navigation changes", function () {
|
||||
beforeEach(function () {
|
||||
mockNavigationService.addListener.mostRecentCall
|
||||
.args[0](mockDomainObject);
|
||||
});
|
||||
|
||||
itNavigatesAsExpected();
|
||||
});
|
||||
|
||||
describe("when mutation occurs", function () {
|
||||
beforeEach(function () {
|
||||
mockMutationTopic.listen.mostRecentCall
|
||||
.args[0](mockParentObject);
|
||||
});
|
||||
|
||||
itNavigatesAsExpected();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -170,7 +170,7 @@ define([
|
||||
"navigationService",
|
||||
"$log"
|
||||
],
|
||||
"description": "Edit",
|
||||
"description": "Edit this object.",
|
||||
"category": "view-control",
|
||||
"glyph": "p"
|
||||
},
|
||||
@@ -206,9 +206,7 @@ define([
|
||||
"implementation": SaveAction,
|
||||
"name": "Save",
|
||||
"description": "Save changes made to these objects.",
|
||||
"depends": [
|
||||
"dialogService"
|
||||
],
|
||||
"depends": [],
|
||||
"priority": "mandatory"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -36,14 +36,14 @@
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pane right menu-item-description l-flex-col">
|
||||
<div class="desc-area flex-elem holder ui-symbol icon type-icon">
|
||||
<div class="pane right menu-item-description">
|
||||
<div class="desc-area ui-symbol icon type-icon">
|
||||
{{representation.activeMetadata.glyph}}
|
||||
</div>
|
||||
<div class="desc-area flex-elem holder title">
|
||||
<div class="desc-area title">
|
||||
{{representation.activeMetadata.name}}
|
||||
</div>
|
||||
<div class="desc-area flex-elem holder description">
|
||||
<div class="desc-area description">
|
||||
{{representation.activeMetadata.description}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -50,24 +50,18 @@ define(
|
||||
//If the object existed already, navigate to refresh view
|
||||
// with previous object state.
|
||||
if (domainObject.getModel().persisted) {
|
||||
return domainObject.getCapability("action").perform("navigate");
|
||||
domainObject.getCapability("action").perform("navigate");
|
||||
} else {
|
||||
//If the object was new, and user has cancelled, then
|
||||
//navigate back to parent because nothing to show.
|
||||
return domainObject.getCapability("location").getOriginal().then(function (original) {
|
||||
domainObject.getCapability("location").getOriginal().then(function (original) {
|
||||
parent = original.getCapability("context").getParent();
|
||||
parent.getCapability("action").perform("navigate");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function cancel(allowed) {
|
||||
return allowed && domainObject.getCapability("editor").cancel();
|
||||
}
|
||||
|
||||
//Do navigation first in order to trigger unsaved changes dialog
|
||||
return returnToBrowse()
|
||||
.then(cancel);
|
||||
return this.domainObject.getCapability("editor").cancel()
|
||||
.then(returnToBrowse);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['./SaveInProgressDialog'],
|
||||
function (SaveInProgressDialog) {
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* The "Save" action; the action triggered by clicking Save from
|
||||
@@ -33,11 +33,9 @@ define(
|
||||
* @memberof platform/commonUI/edit
|
||||
*/
|
||||
function SaveAction(
|
||||
dialogService,
|
||||
context
|
||||
) {
|
||||
this.domainObject = (context || {}).domainObject;
|
||||
this.dialogService = dialogService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,8 +46,7 @@ define(
|
||||
* @memberof platform/commonUI/edit.SaveAction#
|
||||
*/
|
||||
SaveAction.prototype.perform = function () {
|
||||
var domainObject = this.domainObject,
|
||||
dialog = new SaveInProgressDialog(this.dialogService);
|
||||
var domainObject = this.domainObject;
|
||||
|
||||
function resolveWith(object) {
|
||||
return function () {
|
||||
@@ -75,17 +72,8 @@ define(
|
||||
return object;
|
||||
}
|
||||
|
||||
function hideBlockingDialog(object) {
|
||||
dialog.hide();
|
||||
return object;
|
||||
}
|
||||
|
||||
dialog.show();
|
||||
|
||||
return doSave()
|
||||
.then(hideBlockingDialog)
|
||||
.then(returnToBrowse)
|
||||
.catch(hideBlockingDialog);
|
||||
//return doSave().then(returnToBrowse);
|
||||
return doSave().then(returnToBrowse);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,14 +21,9 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
define([
|
||||
'../creation/CreateWizard',
|
||||
'./SaveInProgressDialog'
|
||||
],
|
||||
function (
|
||||
CreateWizard,
|
||||
SaveInProgressDialog
|
||||
) {
|
||||
define(
|
||||
['../creation/CreateWizard'],
|
||||
function (CreateWizard) {
|
||||
|
||||
/**
|
||||
* The "Save" action; the action triggered by clicking Save from
|
||||
@@ -110,8 +105,7 @@ define([
|
||||
SaveAsAction.prototype.save = function () {
|
||||
var self = this,
|
||||
domainObject = this.domainObject,
|
||||
copyService = this.copyService,
|
||||
dialog = new SaveInProgressDialog(this.dialogService);
|
||||
copyService = this.copyService;
|
||||
|
||||
function doWizardSave(parent) {
|
||||
var wizard = self.createWizard(parent);
|
||||
@@ -122,16 +116,6 @@ define([
|
||||
).then(wizard.populateObjectFromInput.bind(wizard));
|
||||
}
|
||||
|
||||
function showBlockingDialog(object) {
|
||||
dialog.show();
|
||||
return object;
|
||||
}
|
||||
|
||||
function hideBlockingDialog(object) {
|
||||
dialog.hide();
|
||||
return object;
|
||||
}
|
||||
|
||||
function fetchObject(objectId) {
|
||||
return self.getObjectService().getObjects([objectId]).then(function (objects) {
|
||||
return objects[objectId];
|
||||
@@ -156,22 +140,14 @@ define([
|
||||
.then(resolveWith(clonedObject));
|
||||
}
|
||||
|
||||
function onFailure() {
|
||||
hideBlockingDialog();
|
||||
return false;
|
||||
}
|
||||
|
||||
return getParent(domainObject)
|
||||
.then(doWizardSave)
|
||||
.then(showBlockingDialog)
|
||||
.then(getParent)
|
||||
.then(cloneIntoParent)
|
||||
.then(commitEditingAfterClone)
|
||||
.then(hideBlockingDialog)
|
||||
.catch(onFailure);
|
||||
.catch(resolveWith(false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if this action is applicable in a given context.
|
||||
* This will ensure that a domain object is present in the context,
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
define([], function () {
|
||||
function SaveInProgressDialog(dialogService) {
|
||||
this.dialogService = dialogService;
|
||||
}
|
||||
|
||||
SaveInProgressDialog.prototype.show = function () {
|
||||
this.dialogService.showBlockingMessage({
|
||||
title: "Saving...",
|
||||
hint: "Do not navigate away from this page or close this browser tab while this message is displayed.",
|
||||
unknownProgress: true,
|
||||
severity: "info"
|
||||
});
|
||||
};
|
||||
|
||||
SaveInProgressDialog.prototype.hide = function () {
|
||||
this.dialogService.dismiss();
|
||||
};
|
||||
|
||||
return SaveInProgressDialog;
|
||||
});
|
||||
@@ -67,17 +67,10 @@ define(
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
if (self.domainObject.getModel().persisted !== undefined) {
|
||||
//Fetch clean model from persistence
|
||||
return self.persistenceCapability.refresh().then(function (result) {
|
||||
self.persistPending = false;
|
||||
return result;
|
||||
});
|
||||
} else {
|
||||
return self.persistenceCapability.refresh().then(function (result) {
|
||||
self.persistPending = false;
|
||||
//Model is undefined in persistence, so return undefined.
|
||||
return self.$q.when(undefined);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
if (this.transactionService.isActive()) {
|
||||
|
||||
@@ -24,11 +24,12 @@ define(
|
||||
["../../src/actions/CancelAction"],
|
||||
function (CancelAction) {
|
||||
|
||||
describe("The Cancel action", function () {
|
||||
var mockDomainObject,
|
||||
mockParentObject,
|
||||
capabilities = {},
|
||||
parentCapabilities = {},
|
||||
//TODO: Disabled for NEM Beta
|
||||
xdescribe("The Cancel action", function () {
|
||||
var mockLocation,
|
||||
mockDomainObject,
|
||||
mockEditorCapability,
|
||||
mockUrlService,
|
||||
actionContext,
|
||||
action;
|
||||
|
||||
@@ -41,114 +42,61 @@ define(
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockLocation = jasmine.createSpyObj(
|
||||
"$location",
|
||||
["path"]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[
|
||||
"getCapability",
|
||||
"hasCapability",
|
||||
"getModel"
|
||||
]
|
||||
["getCapability", "hasCapability"]
|
||||
);
|
||||
mockDomainObject.getModel.andReturn({});
|
||||
|
||||
mockParentObject = jasmine.createSpyObj(
|
||||
"parentObject",
|
||||
[
|
||||
"getCapability"
|
||||
]
|
||||
);
|
||||
mockParentObject.getCapability.andCallFake(function (name) {
|
||||
return parentCapabilities[name];
|
||||
});
|
||||
|
||||
capabilities.editor = jasmine.createSpyObj(
|
||||
mockEditorCapability = jasmine.createSpyObj(
|
||||
"editor",
|
||||
["save", "cancel", "isEditContextRoot"]
|
||||
["save", "cancel"]
|
||||
);
|
||||
capabilities.action = jasmine.createSpyObj(
|
||||
"actionCapability",
|
||||
[
|
||||
"perform"
|
||||
]
|
||||
);
|
||||
capabilities.location = jasmine.createSpyObj(
|
||||
"locationCapability",
|
||||
[
|
||||
"getOriginal"
|
||||
]
|
||||
);
|
||||
capabilities.location.getOriginal.andReturn(mockPromise(mockDomainObject));
|
||||
capabilities.context = jasmine.createSpyObj(
|
||||
"contextCapability",
|
||||
[
|
||||
"getParent"
|
||||
]
|
||||
);
|
||||
capabilities.context.getParent.andReturn(mockParentObject);
|
||||
|
||||
parentCapabilities.action = jasmine.createSpyObj(
|
||||
"actionCapability",
|
||||
[
|
||||
"perform"
|
||||
]
|
||||
mockUrlService = jasmine.createSpyObj(
|
||||
"urlService",
|
||||
["urlForLocation"]
|
||||
);
|
||||
|
||||
actionContext = {
|
||||
domainObject: mockDomainObject
|
||||
};
|
||||
|
||||
mockDomainObject.getCapability.andCallFake(function (name) {
|
||||
return capabilities[name];
|
||||
});
|
||||
mockDomainObject.hasCapability.andReturn(true);
|
||||
mockDomainObject.getCapability.andReturn(mockEditorCapability);
|
||||
mockEditorCapability.cancel.andReturn(mockPromise(true));
|
||||
|
||||
mockDomainObject.hasCapability.andCallFake(function (name) {
|
||||
return !!capabilities[name];
|
||||
});
|
||||
|
||||
capabilities.editor.cancel.andReturn(mockPromise(true));
|
||||
|
||||
action = new CancelAction(actionContext);
|
||||
action = new CancelAction(mockLocation, mockUrlService, actionContext);
|
||||
|
||||
});
|
||||
|
||||
it("only applies to domain object that is being edited", function () {
|
||||
capabilities.editor.isEditContextRoot.andReturn(true);
|
||||
it("only applies to domain object with an editor capability", function () {
|
||||
expect(CancelAction.appliesTo(actionContext)).toBeTruthy();
|
||||
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
|
||||
|
||||
capabilities.editor.isEditContextRoot.andReturn(false);
|
||||
expect(CancelAction.appliesTo(actionContext)).toBeFalsy();
|
||||
|
||||
mockDomainObject.hasCapability.andReturn(false);
|
||||
mockDomainObject.getCapability.andReturn(undefined);
|
||||
expect(CancelAction.appliesTo(actionContext)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("invokes the editor capability's cancel functionality when" +
|
||||
" performed", function () {
|
||||
mockDomainObject.getModel.andReturn({persisted: 1});
|
||||
//Return true from navigate action
|
||||
capabilities.action.perform.andReturn(mockPromise(true));
|
||||
it("invokes the editor capability's save functionality when performed", function () {
|
||||
// Verify precondition
|
||||
expect(mockEditorCapability.cancel).not.toHaveBeenCalled();
|
||||
action.perform();
|
||||
|
||||
// Should have called cancel
|
||||
expect(capabilities.editor.cancel).toHaveBeenCalled();
|
||||
expect(mockEditorCapability.cancel).toHaveBeenCalled();
|
||||
|
||||
// Definitely shouldn't call save!
|
||||
expect(capabilities.editor.save).not.toHaveBeenCalled();
|
||||
expect(mockEditorCapability.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("navigates to object if existing using navigate action", function () {
|
||||
mockDomainObject.getModel.andReturn({persisted: 1});
|
||||
//Return true from navigate action
|
||||
capabilities.action.perform.andReturn(mockPromise(true));
|
||||
it("returns to browse when performed", function () {
|
||||
action.perform();
|
||||
expect(capabilities.action.perform).toHaveBeenCalledWith("navigate");
|
||||
});
|
||||
|
||||
it("navigates to parent if new using navigate action", function () {
|
||||
mockDomainObject.getModel.andReturn({persisted: undefined});
|
||||
action.perform();
|
||||
expect(parentCapabilities.action.perform).toHaveBeenCalledWith("navigate");
|
||||
expect(mockLocation.path).toHaveBeenCalledWith(
|
||||
mockUrlService.urlForLocation("browse", mockDomainObject)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ define(
|
||||
var mockDomainObject,
|
||||
mockEditorCapability,
|
||||
actionContext,
|
||||
dialogService,
|
||||
mockActionCapability,
|
||||
capabilities = {},
|
||||
action;
|
||||
@@ -37,9 +36,6 @@ define(
|
||||
return {
|
||||
then: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
},
|
||||
catch: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -68,10 +64,6 @@ define(
|
||||
actionContext = {
|
||||
domainObject: mockDomainObject
|
||||
};
|
||||
dialogService = jasmine.createSpyObj(
|
||||
"dialogService",
|
||||
["showBlockingMessage", "dismiss"]
|
||||
);
|
||||
|
||||
mockDomainObject.hasCapability.andReturn(true);
|
||||
mockDomainObject.getCapability.andCallFake(function (capability) {
|
||||
@@ -81,7 +73,8 @@ define(
|
||||
mockEditorCapability.save.andReturn(mockPromise(true));
|
||||
mockEditorCapability.isEditContextRoot.andReturn(true);
|
||||
|
||||
action = new SaveAction(dialogService, actionContext);
|
||||
action = new SaveAction(actionContext);
|
||||
|
||||
});
|
||||
|
||||
it("only applies to domain object with an editor capability", function () {
|
||||
@@ -111,19 +104,6 @@ define(
|
||||
expect(mockActionCapability.perform).toHaveBeenCalledWith("navigate");
|
||||
});
|
||||
|
||||
it("shows a dialog while saving", function () {
|
||||
mockEditorCapability.save.andReturn(new Promise(function () {}));
|
||||
action.perform();
|
||||
expect(dialogService.showBlockingMessage).toHaveBeenCalled();
|
||||
expect(dialogService.dismiss).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("hides a dialog when saving is complete", function () {
|
||||
action.perform();
|
||||
expect(dialogService.showBlockingMessage).toHaveBeenCalled();
|
||||
expect(dialogService.dismiss).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -100,9 +100,7 @@ define(
|
||||
mockDialogService = jasmine.createSpyObj(
|
||||
"dialogService",
|
||||
[
|
||||
"getUserInput",
|
||||
"showBlockingMessage",
|
||||
"dismiss"
|
||||
"getUserInput"
|
||||
]
|
||||
);
|
||||
mockDialogService.getUserInput.andReturn(mockPromise(undefined));
|
||||
@@ -171,19 +169,6 @@ define(
|
||||
expect(mockDialogService.getUserInput).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows a blocking dialog while waiting for save", function () {
|
||||
mockEditorCapability.save.andReturn(new Promise(function () {}));
|
||||
action.perform();
|
||||
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
|
||||
expect(mockDialogService.dismiss).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("hides the blocking dialog after saving", function () {
|
||||
action.perform();
|
||||
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
|
||||
expect(mockDialogService.dismiss).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -57,15 +57,6 @@ define(
|
||||
);
|
||||
mockPersistence.persist.andReturn(fastPromise());
|
||||
mockPersistence.refresh.andReturn(fastPromise());
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[
|
||||
"getModel"
|
||||
]
|
||||
);
|
||||
mockDomainObject.getModel.andReturn({persisted: 1});
|
||||
|
||||
capability = new TransactionalPersistenceCapability(mockQ, mockTransactionService, mockPersistence, mockDomainObject);
|
||||
});
|
||||
|
||||
@@ -87,20 +78,6 @@ define(
|
||||
expect(mockPersistence.refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("if transaction is active, cancel call is queued that refreshes model when appropriate", function () {
|
||||
mockTransactionService.isActive.andReturn(true);
|
||||
capability.persist();
|
||||
expect(mockTransactionService.addToTransaction).toHaveBeenCalled();
|
||||
|
||||
mockDomainObject.getModel.andReturn({});
|
||||
mockTransactionService.addToTransaction.mostRecentCall.args[1]();
|
||||
expect(mockPersistence.refresh).not.toHaveBeenCalled();
|
||||
|
||||
mockDomainObject.getModel.andReturn({persisted: 1});
|
||||
mockTransactionService.addToTransaction.mostRecentCall.args[1]();
|
||||
expect(mockPersistence.refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("persist call is only added to transaction once", function () {
|
||||
mockTransactionService.isActive.andReturn(true);
|
||||
capability.persist();
|
||||
|
||||
@@ -23,12 +23,10 @@
|
||||
define([
|
||||
"./src/FormatProvider",
|
||||
"./src/UTCTimeFormat",
|
||||
"./src/DurationFormat",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
FormatProvider,
|
||||
UTCTimeFormat,
|
||||
DurationFormat,
|
||||
legacyRegistry
|
||||
) {
|
||||
|
||||
@@ -50,10 +48,6 @@ define([
|
||||
{
|
||||
"key": "utc",
|
||||
"implementation": UTCTimeFormat
|
||||
},
|
||||
{
|
||||
"key": "duration",
|
||||
"implementation": DurationFormat
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
],
|
||||
@@ -204,7 +207,6 @@ define([
|
||||
"implementation": TimeRangeController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$timeout",
|
||||
"formatService",
|
||||
"DEFAULT_TIME_FORMAT",
|
||||
"now"
|
||||
@@ -405,6 +407,11 @@ define([
|
||||
"key": "THEME",
|
||||
"value": "unspecified",
|
||||
"priority": "fallback"
|
||||
},
|
||||
{
|
||||
"key": "ASSETS_PATH",
|
||||
"value": ".",
|
||||
"priority": "fallback"
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -100,6 +100,5 @@
|
||||
<glyph unicode="" glyph-name="icon-tabular-realtime" d="M896 960h-768c-70.606-0.215-127.785-57.394-128-127.979v-768.021c0.215-70.606 57.394-127.785 127.979-128h768.021c70.606 0.215 127.785 57.394 128 127.979v768.021c-0.215 70.606-57.394 127.785-127.979 128zM448 668l25.060-25.32c7.916-7.922 18.856-12.822 30.94-12.822s23.024 4.9 30.94 12.822l75.5 76.3c29.97 30.338 71.571 49.128 117.56 49.128s87.59-18.79 117.544-49.112l50.456-50.997v-152.2c-24.111 8.83-44.678 22.255-61.542 39.342l-75.518 76.318c-7.916 7.922-18.856 12.822-30.94 12.822s-23.024-4.9-30.94-12.822l-75.5-76.3c-29.971-30.343-71.575-49.137-117.568-49.137-20.084 0-39.331 3.584-57.137 10.146l1.145 151.831zM320 0h-192c-35.26 0.214-63.786 28.74-64 63.98v128.020h256v-192zM320 256h-256v192h256v-192zM320 512h-256v192h256v-192zM640 0h-256v192h256v-192zM448 323.38v174.5c1.88-1.74 3.74-3.5 5.56-5.34l75.5-76.3c7.916-7.922 18.856-12.822 30.94-12.822s23.024 4.9 30.94 12.822l75.5 76.3c29.966 30.333 71.56 49.119 117.542 49.119 43.28 0 82.673-16.644 112.128-43.879l-0.11-174.399c-1.88 1.74-3.74 3.5-5.56 5.34l-75.5 76.3c-7.916 7.922-18.856 12.822-30.94 12.822s-23.024-4.9-30.94-12.822l-75.5-76.3c-29.966-30.333-71.56-49.119-117.542-49.119-43.28 0-82.673 16.644-112.128 43.879zM960 64c-0.214-35.26-28.74-63.786-63.98-64h-192.020v192h256v-128z" />
|
||||
<glyph unicode="" glyph-name="icon-tabular-lad" d="M896 960h-768c-70.606-0.215-127.785-57.394-128-127.979v-768.021c0.215-70.606 57.394-127.785 127.979-128h768.021c70.606 0.215 127.785 57.394 128 127.979v768.021c-0.215 70.606-57.394 127.785-127.979 128zM64 704h256v-192h-256v192zM64 448h256v-192h-256v192zM128 0c-35.26 0.214-63.786 28.74-64 63.98v128.020h256v-192h-192zM384 0v192h256v-192h-256zM960 64c-0.214-35.26-28.74-63.786-63.98-64h-192.020v192h256v-128zM960 448v-192h-576v192h64v64h-64v192h576v-192h-64v-64h64zM782.32 412.62l-110.32 55.16v172.22c0 17.673-14.327 32-32 32s-32-14.327-32-32v-211.78l145.68-72.84c4.172-2.133 9.1-3.383 14.32-3.383 17.675 0 32.003 14.328 32.003 32.003 0 12.454-7.114 23.247-17.501 28.536z" />
|
||||
<glyph unicode="" glyph-name="icon-tabular-lad-set" d="M128 192v576c-70.606-0.215-127.785-57.394-128-127.979v-576.021c0.215-70.606 57.394-127.785 127.979-128h576.021c70.606 0.215 127.785 57.394 128 127.979l-576 0.021c-70.606 0.215-127.785 57.394-128 127.979zM896 960h-576c-70.606-0.215-127.785-57.394-128-127.979v-576.021c0.215-70.606 57.394-127.785 127.979-128h576.021c70.606 0.215 127.785 57.394 128 127.979v576.021c-0.215 70.606-57.394 127.785-127.979 128zM256 768h192v-128h-192v128zM256 576h192v-192h-192v192zM320 192c-35.26 0.214-63.786 28.74-64 63.98v64.020h192v-128h-128zM512 192v128h192v-128h-192zM960 256c-0.214-35.26-28.74-63.786-63.98-64h-128.020v128h192v-64zM960 384h-448v384h448v-384zM832 480c0.002 0 0.005 0 0.007 0 17.673 0 32 14.327 32 32 0 14.055-9.062 25.994-21.662 30.293l-74.345 24.767v104.94c0 17.673-14.327 32-32 32s-32-14.327-32-32v-151.060l117.88-39.3c3.018-1.040 6.495-1.64 10.113-1.64 0.003 0 0.005 0 0.008 0z" />
|
||||
<glyph unicode="" glyph-name="icon-download" d="M832 384v-255.66l-0.34-0.34-639.66 0.34v255.66h-192v-256c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v256h-192zM512 320l448 448h-256v192h-384v-192h-256l448-448z" />
|
||||
<glyph unicode="" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Binary file not shown.
Binary file not shown.
@@ -1,91 +0,0 @@
|
||||
@include keyframes(rotation) {
|
||||
100% { @include transform(rotate(360deg)); }
|
||||
}
|
||||
|
||||
@include keyframes(rotation-centered) {
|
||||
0% { @include transform(translate(-50%, -50%) rotate(0deg)); }
|
||||
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
|
||||
}
|
||||
|
||||
@include keyframes(clock-hands) {
|
||||
0% { @include transform(translate(-50%, -50%) rotate(0deg)); }
|
||||
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
|
||||
}
|
||||
|
||||
@include keyframes(clock-hands-sticky) {
|
||||
0% {
|
||||
@include transform(translate(-50%, -50%) rotate(0deg));
|
||||
}
|
||||
7% {
|
||||
@include transform(translate(-50%, -50%) rotate(0deg));
|
||||
}
|
||||
8% {
|
||||
@include transform(translate(-50%, -50%) rotate(30deg));
|
||||
}
|
||||
15% {
|
||||
@include transform(translate(-50%, -50%) rotate(30deg));
|
||||
}
|
||||
16% {
|
||||
@include transform(translate(-50%, -50%) rotate(60deg));
|
||||
}
|
||||
24% {
|
||||
@include transform(translate(-50%, -50%) rotate(60deg));
|
||||
}
|
||||
25% {
|
||||
@include transform(translate(-50%, -50%) rotate(90deg));
|
||||
}
|
||||
32% {
|
||||
@include transform(translate(-50%, -50%) rotate(90deg));
|
||||
}
|
||||
33% {
|
||||
@include transform(translate(-50%, -50%) rotate(120deg));
|
||||
}
|
||||
40% {
|
||||
@include transform(translate(-50%, -50%) rotate(120deg));
|
||||
}
|
||||
41% {
|
||||
@include transform(translate(-50%, -50%) rotate(150deg));
|
||||
}
|
||||
49% {
|
||||
@include transform(translate(-50%, -50%) rotate(150deg));
|
||||
}
|
||||
50% {
|
||||
@include transform(translate(-50%, -50%) rotate(180deg));
|
||||
}
|
||||
57% {
|
||||
@include transform(translate(-50%, -50%) rotate(180deg));
|
||||
}
|
||||
58% {
|
||||
@include transform(translate(-50%, -50%) rotate(210deg));
|
||||
}
|
||||
65% {
|
||||
@include transform(translate(-50%, -50%) rotate(210deg));
|
||||
}
|
||||
66% {
|
||||
@include transform(translate(-50%, -50%) rotate(240deg));
|
||||
}
|
||||
74% {
|
||||
@include transform(translate(-50%, -50%) rotate(240deg));
|
||||
}
|
||||
75% {
|
||||
@include transform(translate(-50%, -50%) rotate(270deg));
|
||||
}
|
||||
82% {
|
||||
@include transform(translate(-50%, -50%) rotate(270deg));
|
||||
}
|
||||
83% {
|
||||
@include transform(translate(-50%, -50%) rotate(300deg));
|
||||
}
|
||||
90% {
|
||||
@include transform(translate(-50%, -50%) rotate(300deg));
|
||||
}
|
||||
91% {
|
||||
@include transform(translate(-50%, -50%) rotate(330deg));
|
||||
}
|
||||
99% {
|
||||
@include transform(translate(-50%, -50%) rotate(330deg));
|
||||
}
|
||||
100% {
|
||||
@include transform(translate(-50%, -50%) rotate(360deg));
|
||||
}
|
||||
}
|
||||
@@ -108,9 +108,6 @@
|
||||
&.grows {
|
||||
@include flex(1 1 auto);
|
||||
}
|
||||
&.contents-align-right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.flex-container {
|
||||
// Apply to wrapping elements, mct-includes, etc.
|
||||
@@ -124,18 +121,17 @@
|
||||
.l-flex-row {
|
||||
@include flex-direction(row);
|
||||
&.flex-elem { @include flex(1 1 auto); }
|
||||
> .flex-elem {
|
||||
.flex-elem {
|
||||
height: inherit;
|
||||
line-height: inherit;
|
||||
min-width: 0;
|
||||
&.holder:not(:last-child) { margin-right: $interiorMargin; }
|
||||
}
|
||||
.flex-container { @include flex-direction(row); }
|
||||
}
|
||||
|
||||
.l-flex-col {
|
||||
@include flex-direction(column);
|
||||
> .flex-elem {
|
||||
.flex-elem {
|
||||
min-height: 0;
|
||||
&.holder:not(:last-child) { margin-bottom: $interiorMarginLg; }
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ $uePaneMiniTabW: 10px;
|
||||
$uePaneMiniTabCollapsedW: 11px;
|
||||
$ueEditLeftPaneW: 75%;
|
||||
$treeSearchInputBarH: 25px;
|
||||
$ueTimeControlH: (25px, 6px, 20px);
|
||||
/*************** Panes */
|
||||
$ueTimeControlH: (33px, 18px, 20px);
|
||||
// Panes
|
||||
$ueBrowseLeftPaneTreeMinW: 150px;
|
||||
$ueBrowseLeftPaneTreeMaxW: 35%;
|
||||
$ueBrowseLeftPaneTreeW: 25%;
|
||||
@@ -57,59 +57,48 @@ $ueBrowseRightPaneInspectMinW: 200px;
|
||||
$ueBrowseRightPaneInspectMaxW: 35%;
|
||||
$ueBrowseRightPaneInspectW: 20%;
|
||||
$ueDesktopMinW: 600px;
|
||||
/*************** Overlay */
|
||||
|
||||
// Overlay
|
||||
$ovrTopBarH: 45px;
|
||||
$ovrFooterH: 24px;
|
||||
$overlayMargin: 25px;
|
||||
/*************** Items */
|
||||
// Items
|
||||
$ueBrowseGridItemLg: 200px;
|
||||
$ueBrowseGridItemTopBarH: 20px;
|
||||
$ueBrowseGridItemBottomBarH: 30px;
|
||||
$itemPadLR: 5px;
|
||||
/*************** Tree */
|
||||
// Tree
|
||||
$treeVCW: 10px;
|
||||
$treeTypeIconH: 1.4em; // was 16px
|
||||
$treeTypeIconHPx: 16px;
|
||||
$treeTypeIconW: 18px;
|
||||
$treeContextTriggerW: 20px;
|
||||
/*************** Tabular */
|
||||
// Tabular
|
||||
$tabularHeaderH: 22px; //18px
|
||||
$tabularTdPadLR: $itemPadLR;
|
||||
$tabularTdPadTB: 3px;
|
||||
/*************** Imagery */
|
||||
// Imagery
|
||||
$imageMainControlBarH: 25px;
|
||||
$imageThumbsD: 120px;
|
||||
$imageThumbsWrapperH: $imageThumbsD * 1.4;
|
||||
$imageThumbPad: 1px;
|
||||
/*************** Ticks */
|
||||
// Ticks
|
||||
$ticksH: 25px;
|
||||
$tickLblVMargin: 3px;
|
||||
$tickLblH: 15px;
|
||||
$tickLblW: 50px;
|
||||
$tickH: $ticksH - $tickLblVMargin - $tickLblH;
|
||||
$tickW: 1px;
|
||||
/*************** Plots */
|
||||
$plotYBarW: 60px;
|
||||
$plotYLabelMinH: 20px;
|
||||
$plotYLabelW: 10px;
|
||||
$plotXBarH: 32px;
|
||||
$plotLegendH: 20px;
|
||||
$plotSwatchD: 8px;
|
||||
// 1: Top, 2: right, 3: bottom, 4: left
|
||||
$plotDisplayArea: ($plotLegendH + $interiorMargin, 0, $plotXBarH + $interiorMargin, $plotYBarW);
|
||||
/* min plot height is based on user testing to find minimum useful height */
|
||||
$plotMinH: 95px;
|
||||
/*************** Bubbles */
|
||||
// Bubbles
|
||||
$bubbleArwSize: 10px;
|
||||
$bubblePad: $interiorMargin;
|
||||
$bubbleMinW: 100px;
|
||||
$bubbleMaxW: 300px;
|
||||
/*************** Forms */
|
||||
// Forms
|
||||
$reqSymbolW: 15px;
|
||||
$reqSymbolM: $interiorMargin * 2;
|
||||
$reqSymbolFontSize: 0.7em;
|
||||
$inputTextP: 3px 5px;
|
||||
/*************** Wait Spinner Defaults */
|
||||
// Wait Spinner Defaults
|
||||
$waitSpinnerD: 32px;
|
||||
$waitSpinnerTreeD: 20px;
|
||||
$waitSpinnerBorderW: 5px;
|
||||
@@ -135,8 +124,6 @@ $dirImgs: $dirCommonRes + 'images/';
|
||||
|
||||
/************************** TIMINGS */
|
||||
$controlFadeMs: 100ms;
|
||||
$browseToEditAnimMs: 400ms;
|
||||
$editBorderPulseMs: 500ms;
|
||||
|
||||
/************************** LIMITS */
|
||||
$glyphLimit: '\e603';
|
||||
|
||||
@@ -39,20 +39,15 @@
|
||||
@include pulse($animName: pulse-subtle, $dur: 500ms, $opacity0: 0.7);
|
||||
}
|
||||
|
||||
@mixin animTo($animName, $propName, $propValStart, $propValEnd, $dur: 500ms, $delay: 0) {
|
||||
@include keyframes($animName) {
|
||||
from { #{propName}: $propValStart; }
|
||||
to { #{$propName}: $propValEnd; }
|
||||
@mixin pulseBorder($c: red, $dur: 500ms, $iteration: infinite, $delay: 0s, $opacity0: 0, $opacity100: 1) {
|
||||
@include keyframes(pulseBorder) {
|
||||
0% { border-color: rgba($c, $opacity0); }
|
||||
100% { border-color: rgba($c, $opacity100); }
|
||||
}
|
||||
@include animToParams($animName, $dur: 500ms, $delay: 0)
|
||||
}
|
||||
|
||||
@mixin animToParams($animName, $dur: 500ms, $delay: 0) {
|
||||
@include animation-name($animName);
|
||||
@include animation-name(pulseBorder);
|
||||
@include animation-duration($dur);
|
||||
@include animation-direction(alternate);
|
||||
@include animation-iteration-count($iteration);
|
||||
@include animation-timing-function(ease);
|
||||
@include animation-delay($delay);
|
||||
@include animation-fill-mode(both);
|
||||
@include animation-direction(normal);
|
||||
@include animation-iteration-count(1);
|
||||
@include animation-timing-function(ease-in-out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ input, textarea {
|
||||
input[type="text"],
|
||||
input[type="search"] {
|
||||
vertical-align: baseline;
|
||||
padding: $inputTextP;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
|
||||
@@ -66,7 +66,8 @@
|
||||
}
|
||||
|
||||
.menu .type-icon,
|
||||
.tree-item .type-icon {
|
||||
.tree-item .type-icon,
|
||||
.super-menu.menu .type-icon {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*****************************************************************************/
|
||||
@import "effects";
|
||||
@import "global";
|
||||
@import "animations";
|
||||
@import "archetypes";
|
||||
@import "about";
|
||||
@import "text";
|
||||
@@ -41,7 +40,7 @@
|
||||
@import "controls/lists";
|
||||
@import "controls/menus";
|
||||
@import "controls/messages";
|
||||
@import "controls/time-conductor";
|
||||
@import "controls/time-controller";
|
||||
@import "mobile/controls/menus";
|
||||
|
||||
/********************************* FORMS */
|
||||
|
||||
@@ -185,15 +185,21 @@
|
||||
}
|
||||
|
||||
@mixin sliderTrack($bg: $scrollbarTrackColorBg) {
|
||||
//$b: 1px solid lighten($bg, 30%);
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
@include boxIncised(0.7);
|
||||
background-color: $bg;
|
||||
//border-bottom: $b;
|
||||
//border-right: $b;
|
||||
}
|
||||
|
||||
@mixin controlGrippy($b, $direction: horizontal, $w: 1px, $style: dotted) {
|
||||
//&:before {
|
||||
//@include trans-prop-nice("border-color", 25ms);
|
||||
content: '';
|
||||
display: block;
|
||||
//height: auto;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
@@ -299,6 +305,7 @@
|
||||
border-radius: $controlCr;
|
||||
box-sizing: border-box;
|
||||
color: $fg;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@mixin btnBase($bg: $colorBodyBg, $bgHovColor: none, $fg: $colorBodyFg, $ic: $colorBtnIcon) {
|
||||
@@ -341,6 +348,7 @@
|
||||
display: inline-block;
|
||||
font-family: 'symbolsfont';
|
||||
margin-left: $interiorMarginSm;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@mixin nice-textarea($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||
|
||||
@@ -33,11 +33,18 @@ $pad: $interiorMargin * $baseRatio;
|
||||
|
||||
.s-btn {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
padding: 0 $pad;
|
||||
font-size: 0.7rem;
|
||||
vertical-align: top;
|
||||
@include btnSubtle($colorBtnBg, $colorBtnBgHov, $colorBtnFg, $colorBtnIcon);
|
||||
|
||||
.icon {
|
||||
font-size: 0.8rem;
|
||||
color: $colorKey;
|
||||
}
|
||||
|
||||
.title-label {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&.lg {
|
||||
font-size: 1rem;
|
||||
@@ -51,14 +58,19 @@ $pad: $interiorMargin * $baseRatio;
|
||||
padding: 0 ($pad / $baseRatio) / 2;
|
||||
}
|
||||
|
||||
&.major,
|
||||
&.key-edit,
|
||||
&.key-properties {
|
||||
&.major {
|
||||
$bg: $colorBtnMajorBg;
|
||||
$hc: lighten($bg, 10%);
|
||||
@include btnSubtle($bg, $hc, $colorBtnMajorFg, $colorBtnMajorFg);
|
||||
}
|
||||
|
||||
&:not(.major) {
|
||||
// bg, bgHov, fg, ic
|
||||
@include btnSubtle($colorBtnBg, $colorBtnBgHov, $colorBtnFg, $colorBtnIcon);
|
||||
}
|
||||
&.pause-play {
|
||||
|
||||
}
|
||||
&.t-save:before {
|
||||
content:'\e612';
|
||||
font-family: symbolsfont;
|
||||
@@ -97,22 +109,6 @@ $pad: $interiorMargin * $baseRatio;
|
||||
content: "\000039";
|
||||
}
|
||||
}
|
||||
|
||||
&.t-export {
|
||||
&:before {
|
||||
@extend .ui-symbol;
|
||||
@extend .icon;
|
||||
content: '\e623';
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.title-label {
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
.s-icon-btn {
|
||||
@@ -279,3 +275,4 @@ body.desktop .mini-tab-icon {
|
||||
color: $colorPausedBg !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -420,63 +420,6 @@ input[type="search"] {
|
||||
}
|
||||
}
|
||||
|
||||
@mixin sliderKnob() {
|
||||
$h: 16px;
|
||||
cursor: pointer;
|
||||
width: floor($h/1.75);
|
||||
height: $h;
|
||||
margin-top: 1 + floor($h/2) * -1;
|
||||
@include btnSubtle(pullForward($colorBtnBg, 10%));
|
||||
//border-radius: 50% !important;
|
||||
}
|
||||
|
||||
@mixin sliderKnobRound() {
|
||||
$h: 12px;
|
||||
cursor: pointer;
|
||||
width: $h;
|
||||
height: $h;
|
||||
margin-top: 1 + floor($h/2) * -1;
|
||||
@include btnSubtle(pullForward($colorBtnBg, 10%));
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
// HTML5 range inputs
|
||||
|
||||
-webkit-appearance: none; /* Hides the slider so that custom slider can be made */
|
||||
background: transparent; /* Otherwise white in Chrome */
|
||||
&:focus {
|
||||
outline: none; /* Removes the blue border. */
|
||||
}
|
||||
|
||||
// Thumb
|
||||
&::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
@include sliderKnobRound();
|
||||
}
|
||||
&::-moz-range-thumb {
|
||||
border: none;
|
||||
@include sliderKnobRound();
|
||||
}
|
||||
&::-ms-thumb {
|
||||
border: none;
|
||||
@include sliderKnobRound();
|
||||
}
|
||||
|
||||
// Track
|
||||
&::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
@include sliderTrack();
|
||||
}
|
||||
|
||||
&::-moz-range-track {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
@include sliderTrack();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** DATETIME PICKER */
|
||||
.l-datetime-picker {
|
||||
$r1H: 15px;
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
}
|
||||
.pane {
|
||||
box-sizing: border-box;
|
||||
&.menu-items {
|
||||
&.left {
|
||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||
left: 0;
|
||||
padding-right: $interiorMargin;
|
||||
@@ -183,53 +183,38 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
&.menu-item-description {
|
||||
&.right {
|
||||
left: auto;
|
||||
right: 0;
|
||||
padding: $interiorMargin * 5;
|
||||
width: $prw;
|
||||
.desc-area {
|
||||
&.icon {
|
||||
color: $colorCreateMenuLgIcon;
|
||||
font-size: 8em;
|
||||
margin-bottom: $interiorMargin * 3;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
&.title {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: $interiorMargin * 2;
|
||||
}
|
||||
&.description {
|
||||
color: pushBack($colorCreateMenuText, 20%);
|
||||
font-size: 0.8em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.mini {
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
.pane {
|
||||
&.menu-items {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
&.menu-item-description {
|
||||
padding: $interiorMargin * 3;
|
||||
.desc-area {
|
||||
&.icon {
|
||||
font-size: 4em;
|
||||
}
|
||||
&.title {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.menu-item-description {
|
||||
.desc-area {
|
||||
&.icon {
|
||||
$h: 150px;
|
||||
color: $colorCreateMenuLgIcon;
|
||||
position: relative;
|
||||
font-size: 8em;
|
||||
left: 0;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
margin-bottom: $interiorMargin * 5;
|
||||
text-align: center;
|
||||
}
|
||||
&.title {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
&.description {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 0.8em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.context-menu {
|
||||
font-size: 0.80rem;
|
||||
@@ -266,7 +251,3 @@
|
||||
right: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.menus-up .menu {
|
||||
bottom: $btnStdH; top: auto;
|
||||
}
|
||||
|
||||
@@ -1,376 +0,0 @@
|
||||
@mixin toiLineHovEffects() {
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: $timeControllerToiLineColorHov;
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-conductor-holder {
|
||||
$minW: 500px;
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
min-width: $minW;
|
||||
padding-top: $interiorMargin;
|
||||
}
|
||||
|
||||
.time-conductor-icon {
|
||||
$c: $colorObjHdrIc;
|
||||
$d: 20px;
|
||||
background: $c;
|
||||
border-radius: 4px;
|
||||
height: $d !important;
|
||||
width: $d;
|
||||
position: relative;
|
||||
|
||||
// Icon shape: brackets
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
background: $colorBodyBg;
|
||||
position: absolute;
|
||||
}
|
||||
&:before {
|
||||
$in: 7px;
|
||||
left: $in;
|
||||
top: 0;
|
||||
right: $in;
|
||||
bottom: 0;
|
||||
|
||||
}
|
||||
&:after {
|
||||
$in: 4px;
|
||||
left: $in;
|
||||
top: $in;
|
||||
right: $in;
|
||||
bottom: $in;
|
||||
}
|
||||
|
||||
// Clock hands
|
||||
div[class*="hand"] {
|
||||
$handW: 2px;
|
||||
$handH: 8px;
|
||||
@include transform(translate(-50%, -50%));
|
||||
@include animation-iteration-count(infinite);
|
||||
@include animation-timing-function(linear);
|
||||
position: absolute;
|
||||
height: $handW;
|
||||
width: $handW;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
&:before {
|
||||
background-color: $c;
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: -1px;
|
||||
}
|
||||
&.hand-little {
|
||||
z-index: 2;
|
||||
@include animation-duration(12s);
|
||||
&:before {
|
||||
//background: red;
|
||||
height: ceil($handH * 0.7);
|
||||
}
|
||||
}
|
||||
&.hand-big {
|
||||
z-index: 1;
|
||||
@include animation-duration(1s);
|
||||
&:before {
|
||||
height: $handH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-conductor {
|
||||
$knobHOffset: 0px;
|
||||
$rangeValPad: $interiorMargin;
|
||||
$rangeValOffset: $sliderKnobW + $interiorMargin;
|
||||
$r1H: nth($ueTimeControlH, 1);
|
||||
$r2H: nth($ueTimeControlH, 2);
|
||||
$r3H: nth($ueTimeControlH, 3);
|
||||
|
||||
// Glyphs Todo: replace with refactored CSS approach when that is merged into master
|
||||
$glyphIconFixed: '\e604';
|
||||
$glyphIconRealtime: '\43';
|
||||
$glyphIconLatest: '\44';
|
||||
|
||||
position: relative;
|
||||
|
||||
> .l-row-elem {
|
||||
// First order row elements
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mode-selector .s-menu-btn,
|
||||
.time-delta {
|
||||
&:before {
|
||||
@extend .ui-symbol;
|
||||
}
|
||||
}
|
||||
|
||||
.time-delta {
|
||||
&:before {
|
||||
color: $colorTimeCondKeyBg;
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-conductor-inputs-holder,
|
||||
.l-time-conductor-ticks,
|
||||
.l-time-conductor-zoom-w {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.l-time-conductor-inputs-holder {
|
||||
$trInputW: 180px;
|
||||
$hmInputW: 60px;
|
||||
$ticksBlockerFadeW: 50px;
|
||||
$iconCalendarW: 16px;
|
||||
$wBgColor: $colorBodyBg;
|
||||
|
||||
height: $r1H;
|
||||
z-index: 1;
|
||||
.l-time-range-w {
|
||||
// Wraps a datetime text input field
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
&.start-w {
|
||||
@include background-image(linear-gradient(270deg, transparent, $wBgColor $ticksBlockerFadeW));
|
||||
padding-right: $ticksBlockerFadeW;
|
||||
}
|
||||
&.end-w {
|
||||
@include background-image(linear-gradient(90deg, transparent, $wBgColor $ticksBlockerFadeW));
|
||||
padding-left: $ticksBlockerFadeW;
|
||||
right: 0;
|
||||
text-align: right;
|
||||
}
|
||||
input[type="text"] {
|
||||
@include trans-prop-nice(padding, 250ms);
|
||||
}
|
||||
.time-range-input input {
|
||||
width: $trInputW;
|
||||
}
|
||||
.hrs-min-input input {
|
||||
width: $hmInputW;
|
||||
}
|
||||
.icon-calendar {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-conductor-ticks {
|
||||
$c: $colorTick;
|
||||
height: $r1H;
|
||||
mct-conductor-axis {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.l-axis-holder {
|
||||
height: $r1H;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
svg {
|
||||
text-rendering: geometricPrecision;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
> g {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
path {
|
||||
// Line beneath ticks
|
||||
display: none;
|
||||
}
|
||||
line {
|
||||
// Tick marks
|
||||
stroke: $c;
|
||||
}
|
||||
text {
|
||||
// Tick labels
|
||||
fill: $c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.l-data-visualization {
|
||||
background: $colorTimeCondDataVisBg;
|
||||
height: $r2H;
|
||||
}
|
||||
|
||||
.l-time-conductor-controls {
|
||||
align-items: center;
|
||||
margin-top: $interiorMargin;
|
||||
.l-time-conductor-zoom-w {
|
||||
@include justify-content(flex-end);
|
||||
.time-conductor-zoom {
|
||||
height: $r3H;
|
||||
min-width: 100px;
|
||||
width: 20%;
|
||||
}
|
||||
.time-conductor-zoom-current-range {
|
||||
color: $colorTick;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Fixed
|
||||
&.fixed-mode {
|
||||
.time-conductor-icon div[class*="hand"] {
|
||||
&.hand-little {
|
||||
@include transform(rotate(120deg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Realtime, latest modes
|
||||
&.realtime-mode,
|
||||
&.latest-mode {
|
||||
.time-conductor-icon {
|
||||
background: $colorTimeCondKeyBg;
|
||||
div[class*="hand"] {
|
||||
@include animation-name(clock-hands);
|
||||
&:before {
|
||||
background: $colorTimeCondKeyBg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-conductor-inputs-holder {
|
||||
.l-time-range-input-w {
|
||||
input[type="text"]:not(.error) {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
&:hover,
|
||||
&:focus {
|
||||
@include nice-input();
|
||||
padding: $inputTextP;
|
||||
}
|
||||
}
|
||||
&.start-date {
|
||||
pointer-events: none;
|
||||
}
|
||||
.icon-calendar {
|
||||
display: none;
|
||||
}
|
||||
&.end-date {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.realtime-mode .time-conductor-icon div[class*="hand"] { @include animation-name(clock-hands); }
|
||||
&.latest-mode .time-conductor-icon div[class*="hand"] {
|
||||
@include animation-name(clock-hands-sticky);
|
||||
&.hand-big { @include animation-duration(5s); }
|
||||
&.hand-little { @include animation-duration(60s); }
|
||||
}
|
||||
|
||||
.l-data-visualization {
|
||||
background: $colorTimeCondDataVisRtBg !important
|
||||
}
|
||||
.mode-selector .s-menu-btn {
|
||||
@include btnSubtle($colorTimeCondKeyBg, pullForward($colorTimeCondKeyBg, $ltGamma), $colorTimeCondKeyFg);
|
||||
}
|
||||
}
|
||||
&.fixed-mode {
|
||||
$i: $glyphIconFixed;
|
||||
.mode-selector .s-menu-btn:before {
|
||||
content: $i;
|
||||
}
|
||||
}
|
||||
&.realtime-mode {
|
||||
$i: $glyphIconRealtime;
|
||||
.time-delta:before {
|
||||
content: $i;
|
||||
}
|
||||
.mode-selector .s-menu-btn:before {
|
||||
content: $i;
|
||||
}
|
||||
}
|
||||
&.latest-mode {
|
||||
$i: $glyphIconLatest;
|
||||
.time-delta:before {
|
||||
content: $i;
|
||||
}
|
||||
.mode-selector .s-menu-btn:before {
|
||||
content: $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.s-time-range-val {
|
||||
border-radius: $controlCr;
|
||||
background-color: $colorInputBg;
|
||||
padding: 1px 1px 0 $interiorMargin;
|
||||
}
|
||||
|
||||
/******************************************************************** MOBILE */
|
||||
|
||||
@include phoneandtablet {
|
||||
.l-time-conductor {
|
||||
min-width: 0;
|
||||
.l-time-range-slider-holder,
|
||||
.l-time-conductor-ticks {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include phone {
|
||||
.l-time-conductor {
|
||||
.l-time-conductor-inputs-holder {
|
||||
&.l-flex-row,
|
||||
.l-flex-row {
|
||||
@include align-items(flex-start);
|
||||
}
|
||||
.l-time-range-inputs-elem {
|
||||
&.type-icon {
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
.l-time-conductor-inputs-holder {
|
||||
@include flex-direction(column);
|
||||
.l-time-range-input-w:not(:first-child) {
|
||||
&:not(:first-child) {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
margin-right: 0;
|
||||
}
|
||||
.l-time-range-inputs-elem {
|
||||
&.lbl {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include phonePortrait {
|
||||
.l-time-conductor {
|
||||
.l-time-conductor-inputs-holder {
|
||||
.l-time-conductor-inputs-holder {
|
||||
@include flex(1 1 auto);
|
||||
padding-top: 25px; // Make room for the ever lovin' Time Domain Selector
|
||||
.flex-elem {
|
||||
@include flex(1 1 auto);
|
||||
width: 100%;
|
||||
}
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.l-time-domain-selector {
|
||||
right: auto;
|
||||
left: 20px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
@mixin toiLineHovEffects() {
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: $timeControllerToiLineColorHov;
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-controller {
|
||||
$minW: 500px;
|
||||
$knobHOffset: 0px;
|
||||
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
||||
$rangeValPad: $interiorMargin;
|
||||
$rangeValOffset: $sliderKnobW + $interiorMargin;
|
||||
$timeRangeSliderLROffset: 150px + ($sliderKnobW * 2);
|
||||
$r1H: nth($ueTimeControlH,1); // Not currently used
|
||||
$r2H: nth($ueTimeControlH,2);
|
||||
$r3H: nth($ueTimeControlH,3);
|
||||
|
||||
min-width: $minW;
|
||||
font-size: 0.8rem;
|
||||
|
||||
.l-time-range-inputs-holder,
|
||||
.l-time-range-slider-holder,
|
||||
.l-time-range-ticks-holder
|
||||
{
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
&:not(:first-child) {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
}
|
||||
.l-time-range-slider,
|
||||
.l-time-range-ticks {
|
||||
@include absPosDefault(0, visible);
|
||||
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
padding-top: $interiorMargin;
|
||||
&.l-flex-row,
|
||||
.l-flex-row {
|
||||
@include align-items(center);
|
||||
.flex-elem {
|
||||
height: auto;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
.type-icon {
|
||||
font-size: 120%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.l-time-range-input-w,
|
||||
.l-time-range-inputs-elem {
|
||||
margin-right: $interiorMargin;
|
||||
.lbl {
|
||||
color: $colorPlotLabelFg;
|
||||
}
|
||||
.ui-symbol.icon {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
.l-time-range-input-w {
|
||||
// Wraps a datetime text input field
|
||||
position: relative;
|
||||
input[type="text"] {
|
||||
width: 200px;
|
||||
&.picker-icon {
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
.icon-calendar {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-slider-holder {
|
||||
height: $r2H;
|
||||
.range-holder {
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
border: none;
|
||||
.range {
|
||||
.toi-line {
|
||||
$myC: $timeControllerToiLineColor;
|
||||
$myW: 8px;
|
||||
@include transform(translateX(50%));
|
||||
position: absolute;
|
||||
top: 0; right: 0; bottom: 0px; left: auto;
|
||||
width: $myW;
|
||||
height: auto;
|
||||
z-index: 2;
|
||||
&:before {
|
||||
// Vert line
|
||||
background-color: $myC;
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
||||
width: 1px;
|
||||
}
|
||||
}
|
||||
&:hover .toi-line {
|
||||
@include toiLineHovEffects;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:not(:active) {
|
||||
.knob,
|
||||
.range {
|
||||
@include transition-property(left, right);
|
||||
@include transition-duration(500ms);
|
||||
@include transition-timing-function(ease-in-out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-ticks-holder {
|
||||
height: $r3H;
|
||||
.l-time-range-ticks {
|
||||
border-top: 1px solid $colorTick;
|
||||
.tick {
|
||||
background-color: $colorTick;
|
||||
border:none;
|
||||
height: 5px;
|
||||
width: 1px;
|
||||
margin-left: -1px;
|
||||
position: absolute;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
.l-time-range-tick-label {
|
||||
@include webkitProp(transform, translateX(-50%));
|
||||
color: $colorPlotLabelFg;
|
||||
display: inline-block;
|
||||
font-size: 0.7rem;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
white-space: nowrap;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.knob {
|
||||
z-index: 2;
|
||||
&:before {
|
||||
$mTB: 2px;
|
||||
$grippyW: 3px;
|
||||
$mLR: ($sliderKnobW - $grippyW)/2;
|
||||
@include bgStripes($c: pullForward($sliderColorKnob, 20%), $a: 1, $bgsize: 4px, $angle: 0deg);
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: $mTB; right: $mLR; bottom: $mTB; left: $mLR;
|
||||
}
|
||||
.range-value {
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
font-size: 0.7rem;
|
||||
position: absolute;
|
||||
height: $r2H;
|
||||
line-height: $r2H;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
&:hover {
|
||||
.range-value {
|
||||
color: $sliderColorKnobHov;
|
||||
}
|
||||
}
|
||||
&.knob-l {
|
||||
margin-left: $knobM;
|
||||
.range-value {
|
||||
text-align: right;
|
||||
right: $rangeValOffset;
|
||||
}
|
||||
}
|
||||
&.knob-r {
|
||||
margin-right: $knobM;
|
||||
.range-value {
|
||||
left: $rangeValOffset;
|
||||
}
|
||||
&:hover + .range-holder .range .toi-line {
|
||||
@include toiLineHovEffects;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-domain-selector {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: $interiorMargin;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.s-time-range-val {
|
||||
border-radius: $controlCr;
|
||||
background-color: $colorInputBg;
|
||||
padding: 1px 1px 0 $interiorMargin;
|
||||
}
|
||||
|
||||
/******************************************************************** MOBILE */
|
||||
|
||||
@include phoneandtablet {
|
||||
.l-time-controller {
|
||||
min-width: 0;
|
||||
.l-time-range-slider-holder,
|
||||
.l-time-range-ticks-holder {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include phone {
|
||||
.l-time-controller {
|
||||
.l-time-range-inputs-holder {
|
||||
&.l-flex-row,
|
||||
.l-flex-row {
|
||||
@include align-items(flex-start);
|
||||
}
|
||||
.l-time-range-inputs-elem {
|
||||
&.type-icon {
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
.t-inputs-w {
|
||||
@include flex-direction(column);
|
||||
.l-time-range-input-w:not(:first-child) {
|
||||
&:not(:first-child) {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
margin-right: 0;
|
||||
}
|
||||
.l-time-range-inputs-elem {
|
||||
&.lbl { display: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include phonePortrait {
|
||||
.l-time-controller {
|
||||
.l-time-range-inputs-holder {
|
||||
.t-inputs-w {
|
||||
@include flex(1 1 auto);
|
||||
padding-top: 25px; // Make room for the ever lovin' Time Domain Selector
|
||||
.flex-elem {
|
||||
@include flex(1 1 auto);
|
||||
width: 100%;
|
||||
}
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.l-time-domain-selector {
|
||||
right: auto;
|
||||
left: 20px;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
.l-image-main-wrapper,
|
||||
.l-image-main,
|
||||
.l-image-main-controlbar,
|
||||
.l-image-thumbs-wrapper {
|
||||
@include absPosDefault(0, false);
|
||||
}
|
||||
|
||||
/*************************************** MAIN LAYOUT */
|
||||
.l-image-main-wrapper {
|
||||
//@include test();
|
||||
@if $enableImageryThumbs == true {
|
||||
bottom: $interiorMargin*2 + $imageThumbsWrapperH;
|
||||
}
|
||||
@@ -12,14 +15,16 @@
|
||||
min-width: 150px;
|
||||
.l-image-main {
|
||||
background-color: $colorPlotBg;
|
||||
margin-bottom: $interiorMargin;
|
||||
bottom: $imageMainControlBarH + $interiorMargin;
|
||||
}
|
||||
.l-image-main-controlbar {
|
||||
&.l-flex-row { @include align-items(center); }
|
||||
top: auto;
|
||||
height: $imageMainControlBarH;
|
||||
}
|
||||
}
|
||||
|
||||
.l-image-thumbs-wrapper {
|
||||
//@include test(red);
|
||||
top: auto;
|
||||
height: $imageThumbsWrapperH;
|
||||
}
|
||||
@@ -39,17 +44,24 @@
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.l-image-main {
|
||||
//cursor: crosshair;
|
||||
}
|
||||
|
||||
.l-image-main-controlbar {
|
||||
//@include test();
|
||||
font-size: 0.8em;
|
||||
line-height: inherit;
|
||||
line-height: $imageMainControlBarH;
|
||||
.left, .right {
|
||||
direction: rtl;
|
||||
overflow: hidden;
|
||||
}
|
||||
.left {
|
||||
//@include test(red);
|
||||
text-align: left;
|
||||
}
|
||||
.right {
|
||||
//@include test(green);
|
||||
z-index: 2;
|
||||
}
|
||||
.l-date,
|
||||
@@ -59,6 +71,7 @@
|
||||
.l-mag {
|
||||
direction: ltr;
|
||||
display: inline-block;
|
||||
//white-space: nowrap;
|
||||
&:before {
|
||||
content: "\000049";
|
||||
}
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@include keyframes(rotation) {
|
||||
100% { @include transform(rotate(360deg)); }
|
||||
}
|
||||
|
||||
@include keyframes(rotation-centered) {
|
||||
0% { @include transform(translate(-50%, -50%) rotate(0deg)); }
|
||||
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
|
||||
}
|
||||
|
||||
@mixin spinner($b: 5px, $c: $colorKey) {
|
||||
@include transform-origin(center);
|
||||
@include animation-name(rotation-centered);
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tabular-holder {
|
||||
@include absPosDefault();
|
||||
}
|
||||
|
||||
.tabular,
|
||||
table {
|
||||
box-sizing: border-box;
|
||||
@@ -166,41 +162,4 @@ table {
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************** SPECIFIC TABULAR VIEWS */
|
||||
.tabular-holder {
|
||||
&.t-exportable {
|
||||
$btnExportH: 25px;
|
||||
.l-view-section {
|
||||
top: $btnExportH + $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.child-frame {
|
||||
.tabular-holder {
|
||||
&.t-exportable {
|
||||
$btnExportH: $btnFrameH;
|
||||
.s-btn.t-export {
|
||||
@include trans-prop-nice(opacity, $dur: 50ms);
|
||||
opacity: 0;
|
||||
}
|
||||
.l-view-section {
|
||||
@include trans-prop-nice(top, $dur: 150ms, $delay: 50ms);
|
||||
top: 0;
|
||||
}
|
||||
&:hover {
|
||||
.s-btn.t-export {
|
||||
@include trans-prop-nice(opacity, 150ms, 100ms);
|
||||
opacity: 1;
|
||||
}
|
||||
.l-view-section {
|
||||
@include trans-prop-nice(top, $dur: 150ms);
|
||||
top: $btnExportH + $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,10 +19,12 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.abs.holder-plot {
|
||||
// Fend off the scrollbar when less than min-height;
|
||||
right: $interiorMargin;
|
||||
}
|
||||
$yBarW: 60px;
|
||||
$yLabelW: 10px;
|
||||
$xBarH: 32px;
|
||||
$legendH: 20px;
|
||||
$swatchD: 8px;
|
||||
$plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBarW); // Top, right, bottom, left
|
||||
|
||||
.gl-plot {
|
||||
color: $colorPlotFg;
|
||||
@@ -30,7 +32,6 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: $plotMinH;
|
||||
|
||||
.gl-plot-local-controls {
|
||||
@include trans-prop-nice(opacity, 150ms);
|
||||
@@ -53,17 +54,17 @@
|
||||
top: auto;
|
||||
right: 0;
|
||||
bottom: $interiorMargin;
|
||||
left: $plotYBarW;
|
||||
height: $plotXBarH;
|
||||
left: $yBarW;
|
||||
height: $xBarH;
|
||||
width: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
&.gl-plot-y {
|
||||
top: $plotLegendH + $interiorMargin;
|
||||
top: $legendH + $interiorMargin;
|
||||
right: auto;
|
||||
bottom: nth($plotDisplayArea, 3);
|
||||
left: 0;
|
||||
width: $plotYBarW;
|
||||
width: $yBarW;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +146,7 @@
|
||||
@include transform(translateY(-50%));
|
||||
min-width: 150px; // Need this due to enclosure of .select
|
||||
top: 50%;
|
||||
left: $plotYLabelW + $interiorMargin * 2;
|
||||
left: $yLabelW + $interiorMargin * 2;
|
||||
}
|
||||
|
||||
.t-plot-display-controls {
|
||||
@@ -173,7 +174,7 @@
|
||||
right: 0;
|
||||
bottom: auto;
|
||||
left: 0;
|
||||
height: $plotLegendH;
|
||||
height: $legendH;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -235,8 +236,8 @@
|
||||
.color-swatch {
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
height: $plotSwatchD;
|
||||
width: $plotSwatchD;
|
||||
height: $swatchD;
|
||||
width: $swatchD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,8 +249,8 @@
|
||||
padding: 0px $itemPadLR;
|
||||
.plot-color-swatch {
|
||||
border: 1px solid $colorBodyBg;
|
||||
height: $plotSwatchD + 1;
|
||||
width: $plotSwatchD + 1;
|
||||
height: $swatchD + 1;
|
||||
width: $swatchD + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +54,7 @@
|
||||
height: $ohH;
|
||||
line-height: $ohH;
|
||||
padding: 0 $interiorMargin;
|
||||
> span,
|
||||
&:before {
|
||||
> span {
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,8 +129,6 @@
|
||||
}
|
||||
|
||||
.primary-pane {
|
||||
// Clip element that have min-widths
|
||||
overflow: hidden;
|
||||
// Need to lift up this pane to ensure that 'collapsed' panes don't block user interactions
|
||||
z-index: 4;
|
||||
}
|
||||
@@ -239,10 +237,30 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
}
|
||||
|
||||
.l-object-wrapper {
|
||||
@extend .abs;
|
||||
|
||||
.object-holder-main {
|
||||
@extend .abs;
|
||||
}
|
||||
.l-edit-controls {
|
||||
//@include trans-prop-nice((opacity, height), 0.25s);
|
||||
border-bottom: 1px solid $colorInteriorBorder;
|
||||
line-height: $ueEditToolBarH;
|
||||
height: 0px;
|
||||
opacity: 0;
|
||||
.tool-bar {
|
||||
right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-object-wrapper-inner {
|
||||
@include trans-prop-nice-resize(0.25s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.object-browse-bar .s-btn,
|
||||
.top-bar .buttons-main .s-btn,
|
||||
.top-bar .s-menu-btn,
|
||||
@@ -270,9 +288,8 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
|
||||
|
||||
.left {
|
||||
padding-right: $interiorMarginLg;
|
||||
.l-back {
|
||||
.l-back:not(.s-status-editing) {
|
||||
margin-right: $interiorMarginLg;
|
||||
&.s-status-editing { display: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,49 +376,19 @@ body.desktop {
|
||||
|
||||
.s-status-editing {
|
||||
.l-object-wrapper {
|
||||
$t2Dur: $browseToEditAnimMs;
|
||||
$t1Dur: $t2Dur / 2;
|
||||
$pulseDur: $editBorderPulseMs;
|
||||
$bC0: rgba($colorEditAreaFg, 0.5);
|
||||
$bC100: rgba($colorEditAreaFg, 1);
|
||||
|
||||
background-color: $colorEditAreaBg;
|
||||
@include pulseBorder($colorEditAreaFg, $dur: 1s, $opacity0: 0.3);
|
||||
border-radius: $controlCr;
|
||||
border: 1px dotted $bC0;
|
||||
|
||||
// Transition 1
|
||||
@include keyframes(wrapperIn) {
|
||||
from { border: 0px dotted transparent; padding: 0; }
|
||||
to { border: 1px dotted $bC0; padding: 5px; }
|
||||
background-color: $colorEditAreaBg;
|
||||
border-color: $colorEditAreaFg;
|
||||
border-width: 2px;
|
||||
border-style: dotted;
|
||||
.l-object-wrapper-inner {
|
||||
@include absPosDefault(3px, hidden);
|
||||
}
|
||||
|
||||
// Do last
|
||||
@include keyframes(pulseNew) {
|
||||
from { border-color: $bC0; }
|
||||
to { border-color: $bC100; }
|
||||
}
|
||||
|
||||
@include animation-name(wrapperIn, pulseNew);
|
||||
@include animation-duration($t1Dur, $pulseDur);
|
||||
@include animation-delay(0s, $t1Dur + $t2Dur);
|
||||
@include animation-direction(normal, alternate);
|
||||
@include animation-fill-mode(both, none);
|
||||
@include animation-iteration-count(1, infinite);
|
||||
@include animation-timing-function(ease-in-out, linear);
|
||||
|
||||
|
||||
.l-edit-controls {
|
||||
height: 0;
|
||||
border-bottom: 1px solid $colorInteriorBorder;
|
||||
// Transition 2: reveal edit controls
|
||||
@include keyframes(editIn) {
|
||||
from { border-bottom: 0px solid transparent; height: 0; margin-bottom: 0; }
|
||||
to { border-bottom: 1px solid $colorInteriorBorder; height: $ueEditToolBarH + $interiorMargin; margin-bottom: $interiorMargin; }
|
||||
}
|
||||
@include animToParams(editIn, $dur: $t2Dur, $delay: $t1Dur);
|
||||
.tool-bar {
|
||||
right: $interiorMargin;
|
||||
}
|
||||
height: $ueEditToolBarH + $interiorMargin;
|
||||
margin-bottom: $interiorMargin;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,19 +23,16 @@
|
||||
<input type="text"
|
||||
ng-model="textValue"
|
||||
ng-blur="restoreTextValue(); ngBlur()"
|
||||
ng-mouseup="ngMouseup()"
|
||||
ng-class="{
|
||||
error: textInvalid ||
|
||||
(structure.validate &&
|
||||
!structure.validate(ngModel[field])),
|
||||
'picker-icon': structure.format === 'utc' || !structure.format
|
||||
}">
|
||||
</input>
|
||||
<a class="ui-symbol icon icon-calendar"
|
||||
ng-if="!picker.active && (structure.format === 'utc' || !structure.format)"
|
||||
ng-click="picker.active = !picker.active"></a>
|
||||
<!-- If picker active show icon with no onclick to prevent double registration of clicks -->
|
||||
<a class="ui-symbol icon icon-calendar" ng-if="picker.active"></a>
|
||||
</input><a class="ui-symbol icon icon-calendar"
|
||||
ng-if="structure.format === 'utc' || !structure.format"
|
||||
ng-click="picker.active = !picker.active">
|
||||
</a>
|
||||
<mct-popup ng-if="picker.active">
|
||||
<div mct-click-elsewhere="picker.active = false">
|
||||
<mct-control key="'datetime-picker'"
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-controller="TimeRangeController as trCtrl" class="l-flex-col">
|
||||
<form class="l-time-conductor-inputs-holder l-flex-row flex-elem"
|
||||
<form class="l-time-range-inputs-holder l-flex-row flex-elem"
|
||||
ng-submit="trCtrl.updateBoundsFromForm()">
|
||||
<span class="l-time-range-inputs-elem ui-symbol type-icon flex-elem">C</span>
|
||||
<span class="l-time-range-inputs-elem l-flex-row flex-elem">
|
||||
<span class="l-time-range-inputs-elem t-inputs-w l-flex-row flex-elem">
|
||||
<span class="l-time-range-input-w flex-elem">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
@@ -86,7 +86,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="l-time-conductor-ticks flex-elem">
|
||||
<div class="l-time-range-ticks-holder flex-elem">
|
||||
<div class="l-time-range-ticks">
|
||||
<div
|
||||
ng-repeat="tick in ticks track by $index"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -72,17 +72,6 @@ define(
|
||||
if ($scope.ngBlur) {
|
||||
$scope.ngBlur();
|
||||
}
|
||||
|
||||
// If picker is active, dismiss it when valid value has been selected
|
||||
// This 'if' is to avoid unnecessary validation if picker is not active
|
||||
if ($scope.picker.active) {
|
||||
if ($scope.structure.validate && $scope.structure.validate($scope.ngModel[$scope.field])) {
|
||||
$scope.picker.active = false;
|
||||
} else if (!$scope.structure.validate) {
|
||||
//If picker visible, but no validation function, hide picker
|
||||
$scope.picker.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +93,7 @@ define(
|
||||
$scope.$watch('ngModel[field]', updateFromModel);
|
||||
$scope.$watch('pickerModel.value', updateFromPicker);
|
||||
$scope.$watch('textValue', updateFromView);
|
||||
|
||||
}
|
||||
|
||||
return DateTimeFieldController;
|
||||
|
||||
@@ -53,7 +53,7 @@ define([
|
||||
* format has been otherwise specified
|
||||
* @param {Function} now a function to return current system time
|
||||
*/
|
||||
function TimeRangeController($scope, $timeout, formatService, defaultFormat, now) {
|
||||
function TimeRangeController($scope, formatService, defaultFormat, now) {
|
||||
this.$scope = $scope;
|
||||
this.formatService = formatService;
|
||||
this.defaultFormat = defaultFormat;
|
||||
@@ -66,7 +66,6 @@ define([
|
||||
this.formatter = formatService.getFormat(defaultFormat);
|
||||
this.formStartChanged = false;
|
||||
this.formEndChanged = false;
|
||||
this.$timeout = $timeout;
|
||||
|
||||
this.$scope.ticks = [];
|
||||
|
||||
@@ -260,23 +259,18 @@ define([
|
||||
};
|
||||
|
||||
TimeRangeController.prototype.updateBoundsFromForm = function () {
|
||||
var self = this;
|
||||
|
||||
//Allow Angular to trigger watches and determine whether values have changed.
|
||||
this.$timeout(function () {
|
||||
if (self.formStartChanged) {
|
||||
self.$scope.ngModel.outer.start =
|
||||
self.$scope.ngModel.inner.start =
|
||||
self.$scope.formModel.start;
|
||||
self.formStartChanged = false;
|
||||
}
|
||||
if (self.formEndChanged) {
|
||||
self.$scope.ngModel.outer.end =
|
||||
self.$scope.ngModel.inner.end =
|
||||
self.$scope.formModel.end;
|
||||
self.formEndChanged = false;
|
||||
}
|
||||
});
|
||||
if (this.formStartChanged) {
|
||||
this.$scope.ngModel.outer.start =
|
||||
this.$scope.ngModel.inner.start =
|
||||
this.$scope.formModel.start;
|
||||
this.formStartChanged = false;
|
||||
}
|
||||
if (this.formEndChanged) {
|
||||
this.$scope.ngModel.outer.end =
|
||||
this.$scope.ngModel.inner.end =
|
||||
this.$scope.formModel.end;
|
||||
this.formEndChanged = false;
|
||||
}
|
||||
};
|
||||
|
||||
TimeRangeController.prototype.onFormStartChange = function (
|
||||
|
||||
@@ -51,9 +51,7 @@ define(
|
||||
yMax = yMin + rect.height;
|
||||
|
||||
if (x < xMin || x > xMax || y < yMin || y > yMax) {
|
||||
scope.$apply(function () {
|
||||
scope.$eval(attrs.mctClickElsewhere);
|
||||
});
|
||||
scope.$eval(attrs.mctClickElsewhere);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ define(
|
||||
var mockScope,
|
||||
mockFormatService,
|
||||
testDefaultFormat,
|
||||
mockTimeout,
|
||||
mockNow,
|
||||
mockFormat,
|
||||
controller;
|
||||
@@ -55,10 +54,6 @@ define(
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockTimeout = function (fn) {
|
||||
return fn();
|
||||
};
|
||||
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$apply", "$watch", "$watchCollection"]
|
||||
@@ -83,7 +78,6 @@ define(
|
||||
|
||||
controller = new TimeRangeController(
|
||||
mockScope,
|
||||
mockTimeout,
|
||||
mockFormatService,
|
||||
testDefaultFormat,
|
||||
mockNow
|
||||
|
||||
@@ -104,8 +104,6 @@ define(
|
||||
});
|
||||
|
||||
it("triggers an evaluation of its related Angular expression", function () {
|
||||
expect(mockScope.$apply).toHaveBeenCalled();
|
||||
mockScope.$apply.mostRecentCall.args[0]();
|
||||
expect(mockScope.$eval)
|
||||
.toHaveBeenCalledWith(testAttrs.mctClickElsewhere);
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ $colorAHov: #fff;
|
||||
$contrastRatioPercent: 7%;
|
||||
$hoverRatioPercent: 10%;
|
||||
$basicCr: 3px;
|
||||
$controlCr: 2px;
|
||||
$controlCr: 3px;
|
||||
$smallCr: 2px;
|
||||
|
||||
// Buttons and Controls
|
||||
@@ -52,7 +52,7 @@ $colorGridLines: rgba(#fff, 0.05);
|
||||
$colorInvokeMenu: #fff;
|
||||
$colorObjHdrTxt: $colorBodyFg;
|
||||
$colorObjHdrIc: pullForward($colorObjHdrTxt, 20%);
|
||||
$colorTick: pullForward($colorBodyBg, 20%);
|
||||
$colorTick: rgba(white, 0.2);
|
||||
|
||||
// Menu colors
|
||||
$colorMenuBg: pullForward($colorBodyBg, 23%);
|
||||
@@ -183,13 +183,12 @@ $scrollbarThumbColorOverlay: lighten($colorOvrBg, 10%);
|
||||
$scrollbarThumbColorOverlayHov: lighten($scrollbarThumbColorOverlay, 2%);
|
||||
|
||||
// Splitter
|
||||
$splitterD: 17px; // splitterD and $splitterHandleD should both be odd, or even
|
||||
$splitterD: 25px; // splitterD and HandleD should both be odd, or even
|
||||
$splitterHandleD: 1px;
|
||||
$splitterDSm: 17px; // Smaller splitter, used inside elements like a Timeline view
|
||||
$colorSplitterBg: rgba(#fff, 0.1); //pullForward($colorBodyBg, 5%);
|
||||
$splitterShdw: rgba(black, 0.4) 0 0 3px;
|
||||
$splitterEndCr: none;
|
||||
$colorSplitterHover: pullForward($colorBodyBg, 40%);
|
||||
$colorSplitterHover: pullForward($colorBodyBg, 15%);
|
||||
$colorSplitterActive: $colorKey;
|
||||
|
||||
// Mobile
|
||||
@@ -207,10 +206,4 @@ $colorAboutLink: #84b3ff;
|
||||
|
||||
// Loading
|
||||
$colorLoadingFg: $colorAlt1;
|
||||
$colorLoadingBg: rgba($colorBodyFg, 0.2);
|
||||
|
||||
// Time Conductor
|
||||
$colorTimeCondKeyBg: #4e70dc;
|
||||
$colorTimeCondKeyFg: #fff;
|
||||
$colorTimeCondDataVisBg: pullForward($colorBodyBg, 10%);
|
||||
$colorTimeCondDataVisRtBg: pushBack($colorTimeCondKeyBg, 10%);
|
||||
$colorLoadingBg: rgba($colorBodyFg, 0.2);
|
||||
@@ -52,7 +52,7 @@ $colorGridLines: rgba(#000, 0.05);
|
||||
$colorInvokeMenu: #fff;
|
||||
$colorObjHdrTxt: $colorBodyFg;
|
||||
$colorObjHdrIc: pushBack($colorObjHdrTxt, 30%);
|
||||
$colorTick: pullForward($colorBodyBg, 30%);
|
||||
$colorTick: rgba(black, 0.2);
|
||||
|
||||
// Menu colors
|
||||
$colorMenuBg: pushBack($colorBodyBg, 10%);
|
||||
@@ -183,13 +183,12 @@ $scrollbarThumbColorOverlay: darken($colorOvrBg, 50%);
|
||||
$scrollbarThumbColorOverlayHov: $scrollbarThumbColorHov;
|
||||
|
||||
// Splitter
|
||||
$splitterD: 16px; // splitterD and $splitterHandleD should both be odd, or even
|
||||
$splitterD: 24px;
|
||||
$splitterHandleD: 2px;
|
||||
$splitterDSm: 16px; // Smaller splitter, used inside elements like a Timeline view
|
||||
$colorSplitterBg: pullForward($colorBodyBg, 10%);
|
||||
$splitterShdw: none;
|
||||
$splitterEndCr: none;
|
||||
$colorSplitterHover: pullForward($colorBodyBg, 30%);
|
||||
$colorSplitterHover: none;
|
||||
$colorSplitterActive: $colorKey;
|
||||
|
||||
// Mobile
|
||||
@@ -208,9 +207,3 @@ $colorAboutLink: #84b3ff;
|
||||
// Loading
|
||||
$colorLoadingFg: $colorAlt1;
|
||||
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
||||
|
||||
// Time Conductor
|
||||
$colorTimeCondKeyBg: #6178dc;
|
||||
$colorTimeCondKeyFg: #fff;
|
||||
$colorTimeCondDataVisBg: pullForward($colorBodyBg, 10%);
|
||||
$colorTimeCondDataVisRtBg: pushBack($colorTimeCondKeyBg, 30%);
|
||||
|
||||
@@ -60,6 +60,11 @@ define(
|
||||
this.$q = $q;
|
||||
}
|
||||
|
||||
function getKey(id) {
|
||||
var parts = id.split(":");
|
||||
return parts.length > 1 ? parts.slice(1).join(":") : id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value returned is falsey, and if so returns a
|
||||
* rejected promise
|
||||
@@ -126,7 +131,7 @@ define(
|
||||
// ...and persist
|
||||
return persistenceFn.apply(persistenceService, [
|
||||
this.getSpace(),
|
||||
this.getKey(),
|
||||
getKey(domainObject.getId()),
|
||||
domainObject.getModel()
|
||||
]).then(function (result) {
|
||||
return rejectIfFalsey(result, self.$q);
|
||||
@@ -154,7 +159,7 @@ define(
|
||||
|
||||
return this.persistenceService.readObject(
|
||||
this.getSpace(),
|
||||
this.getKey()
|
||||
this.domainObject.getId()
|
||||
).then(updateModel);
|
||||
};
|
||||
|
||||
@@ -173,17 +178,6 @@ define(
|
||||
return this.identifierService.parse(id).getSpace();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the key for this domain object in the given space.
|
||||
*
|
||||
* @returns {string} the key of the object in it's space.
|
||||
*/
|
||||
PersistenceCapability.prototype.getKey = function () {
|
||||
var id = this.domainObject.getId();
|
||||
return this.identifierService.parse(id).getKey();
|
||||
};
|
||||
|
||||
return PersistenceCapability;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -35,8 +35,7 @@ define(
|
||||
mockNofificationService,
|
||||
mockCacheService,
|
||||
mockQ,
|
||||
key = "persistence key",
|
||||
id = "object identifier",
|
||||
id = "object id",
|
||||
model,
|
||||
SPACE = "some space",
|
||||
persistence,
|
||||
@@ -102,7 +101,6 @@ define(
|
||||
});
|
||||
mockIdentifierService.parse.andReturn(mockIdentifier);
|
||||
mockIdentifier.getSpace.andReturn(SPACE);
|
||||
mockIdentifier.getKey.andReturn(key);
|
||||
persistence = new PersistenceCapability(
|
||||
mockCacheService,
|
||||
mockPersistenceService,
|
||||
@@ -126,7 +124,7 @@ define(
|
||||
|
||||
expect(mockPersistenceService.createObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
key,
|
||||
id,
|
||||
model
|
||||
);
|
||||
});
|
||||
@@ -140,7 +138,7 @@ define(
|
||||
|
||||
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
key,
|
||||
id,
|
||||
model
|
||||
);
|
||||
});
|
||||
|
||||
@@ -82,6 +82,16 @@ define(
|
||||
expect(result.a.getModel()).toEqual(model);
|
||||
});
|
||||
|
||||
//TODO: Disabled for NEM Beta
|
||||
xit("provides a new, fully constituted domain object for a" +
|
||||
" provided model", function () {
|
||||
var model = { someKey: "some value"},
|
||||
result;
|
||||
result = provider.newObject("a", model);
|
||||
expect(result.getId()).toEqual("a");
|
||||
expect(result.getModel()).toEqual(model);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -81,7 +81,6 @@ define(
|
||||
if (phase.toLowerCase() === 'preparing' && !this.dialog) {
|
||||
this.dialog = this.dialogService.showBlockingMessage({
|
||||
title: "Preparing to copy objects",
|
||||
hint: "Do not navigate away from this page or close this browser tab while this message is displayed.",
|
||||
unknownProgress: true,
|
||||
severity: "info"
|
||||
});
|
||||
|
||||
@@ -24,7 +24,10 @@ define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
var DISALLOWED_ACTIONS = ["move"];
|
||||
var DISALLOWED_ACTIONS = [
|
||||
"move",
|
||||
"copy"
|
||||
];
|
||||
|
||||
/**
|
||||
* This policy prevents performing move/copy/link actions across
|
||||
|
||||
@@ -70,25 +70,27 @@ define(
|
||||
policy = new CrossSpacePolicy();
|
||||
});
|
||||
|
||||
describe("for move actions", function () {
|
||||
beforeEach(function () {
|
||||
testActionMetadata.key = 'move';
|
||||
});
|
||||
['move', 'copy'].forEach(function (key) {
|
||||
describe("for " + key + " actions", function () {
|
||||
beforeEach(function () {
|
||||
testActionMetadata.key = key;
|
||||
});
|
||||
|
||||
it("allows same-space changes", function () {
|
||||
expect(policy.allow(mockAction, sameSpaceContext))
|
||||
.toBe(true);
|
||||
});
|
||||
it("allows same-space changes", function () {
|
||||
expect(policy.allow(mockAction, sameSpaceContext))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("disallows cross-space changes", function () {
|
||||
expect(policy.allow(mockAction, crossSpaceContext))
|
||||
.toBe(false);
|
||||
});
|
||||
it("disallows cross-space changes", function () {
|
||||
expect(policy.allow(mockAction, crossSpaceContext))
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
it("allows actions with no selectedObject", function () {
|
||||
expect(policy.allow(mockAction, {
|
||||
domainObject: makeObject('a')
|
||||
})).toBe(true);
|
||||
it("allows actions with no selectedObject", function () {
|
||||
expect(policy.allow(mockAction, {
|
||||
domainObject: makeObject('a')
|
||||
})).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"./src/TimeConductor",
|
||||
"./src/ui/TimeConductorController",
|
||||
"./src/ui/MCTConductorAxis",
|
||||
"./src/timeSystems/UTCTimeSystem",
|
||||
"text!./res/templates/time-conductor.html",
|
||||
"text!./res/templates/mode-selector/mode-selector.html",
|
||||
"text!./res/templates/mode-selector/mode-menu.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
TimeConductor,
|
||||
TimeConductorController,
|
||||
MCTConductorAxis,
|
||||
UTCTimeSystem,
|
||||
timeConductorTemplate,
|
||||
modeSelectorTemplate,
|
||||
modeMenuTemplate,
|
||||
legacyRegistry
|
||||
) {
|
||||
|
||||
legacyRegistry.register("platform/features/conductor-v2", {
|
||||
"extensions": {
|
||||
"services": [
|
||||
{
|
||||
"key": "timeConductor",
|
||||
"implementation": TimeConductor
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "TimeConductorController",
|
||||
"implementation": TimeConductorController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"timeConductor",
|
||||
"timeSystems[]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctConductorAxis",
|
||||
"implementation": MCTConductorAxis,
|
||||
"depends": [
|
||||
"timeConductor"
|
||||
]
|
||||
}
|
||||
],
|
||||
"representations": [
|
||||
{
|
||||
"key": "time-conductor",
|
||||
"template": timeConductorTemplate
|
||||
},
|
||||
{
|
||||
"key": "mode-selector",
|
||||
"template": modeSelectorTemplate
|
||||
},
|
||||
{
|
||||
"key": "mode-menu",
|
||||
"template": modeMenuTemplate
|
||||
}
|
||||
],
|
||||
"timeSystems": [
|
||||
{
|
||||
"implementation": UTCTimeSystem,
|
||||
"depends": ["$timeout"]
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
<!--
|
||||
Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT Web includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="contents">
|
||||
<div class="pane left menu-items">
|
||||
<ul>
|
||||
<li ng-repeat="option in ngModel.options"
|
||||
ng-click="ngModel.selected=option">
|
||||
<a
|
||||
ng-mouseover="representation.activeMetadata = option.metadata"
|
||||
ng-mouseleave="representation.activeMetadata = undefined">
|
||||
<span class="ui-symbol icon type-icon">
|
||||
{{option.metadata.glyph}}
|
||||
</span>
|
||||
{{option.metadata.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pane right menu-item-description">
|
||||
<div class="desc-area ui-symbol icon type-icon">
|
||||
{{representation.activeMetadata.glyph}}
|
||||
</div>
|
||||
<div class="desc-area title">
|
||||
{{representation.activeMetadata.name}}
|
||||
</div>
|
||||
<div class="desc-area description">
|
||||
{{representation.activeMetadata.description}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,34 +0,0 @@
|
||||
<!--
|
||||
Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT Web includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span ng-controller="ClickAwayController as modeController">
|
||||
<div class="s-menu-btn"
|
||||
ng-click="modeController.toggle()">
|
||||
<span class="title-label">{{ngModel.selected.metadata.label}}</span>
|
||||
</div>
|
||||
<div class="menu super-menu mini mode-selector-menu"
|
||||
ng-show="modeController.isActive()">
|
||||
<mct-representation mct-object="domainObject"
|
||||
key="'mode-menu'"
|
||||
ng-model="ngModel">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</span>
|
||||
@@ -1,107 +0,0 @@
|
||||
<!-- Parent holder for time conductor. follow-mode | fixed-mode -->
|
||||
<div ng-controller="TimeConductorController as tcController"
|
||||
class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selected.metadata.key}}-mode {{timeSystemModel.selected.metadata.key}}-time-system">
|
||||
|
||||
<div class="flex-elem holder time-conductor-icon">
|
||||
<div class="hand-little"></div>
|
||||
<div class="hand-big"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex-elem holder grows l-flex-col l-time-conductor-inner">
|
||||
<!-- Holds inputs and ticks -->
|
||||
<div class="l-time-conductor-ticks l-row-elem l-flex-row flex-elem no-margin">
|
||||
<form class="abs l-time-conductor-inputs-holder"
|
||||
ng-submit="tcController.updateBoundsFromForm(formModel)">
|
||||
<span class="l-time-range-w start-w">
|
||||
<span class="l-time-range-input-w start-date">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: timeSystemModel.format,
|
||||
validate: tcController.validation.validateStart
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-mouseup="changing['start'] = true"
|
||||
ng-blur="changing['start'] = false; tcController.updateBoundsFromForm(formModel)"
|
||||
field="'start'"
|
||||
class="time-range-input">
|
||||
</mct-control>
|
||||
</span>
|
||||
<span class="l-time-range-input-w time-delta start-delta"
|
||||
ng-class="{'hide':(modeModel.selected.metadata.key === 'fixed')}">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: 'duration',
|
||||
validate: tcController.validation.validateStartDelta
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-blur="tcController.updateDeltasFromForm(formModel)"
|
||||
field="'startDelta'"
|
||||
class="hrs-min-input">
|
||||
</mct-control>
|
||||
</span>
|
||||
</span>
|
||||
<span class="l-time-range-w end-w">
|
||||
<span class="l-time-range-input-w time-delta end-delta"
|
||||
ng-class="{'hide':(modeModel.selected.metadata.key === 'fixed')}">
|
||||
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: 'duration',
|
||||
validate: tcController.validation.validateEndDelta
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-blur="tcController.updateDeltasFromForm(formModel)"
|
||||
field="'endDelta'"
|
||||
class="hrs-min-input">
|
||||
</mct-control>
|
||||
</span>
|
||||
<span class="l-time-range-input-w end-date"
|
||||
ng-controller="ToggleController as t2">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: timeSystemModel.format,
|
||||
validate: tcController.validation.validateEnd
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-mouseup="changing['end'] = true"
|
||||
ng-blur="changing['end'] = false; tcController.updateBoundsFromForm(formModel)"
|
||||
field="'end'"
|
||||
class="time-range-input">
|
||||
</mct-control>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<input type="submit" class="hidden">
|
||||
</form>
|
||||
<mct-conductor-axis></mct-conductor-axis>
|
||||
</div>
|
||||
|
||||
<!-- Holds data availability, time of interest -->
|
||||
<div class="l-data-visualization l-row-elem l-flex-row flex-elem"></div>
|
||||
|
||||
<!-- Holds time system and session selectors, and zoom control -->
|
||||
<div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem">
|
||||
<mct-representation
|
||||
key="'mode-selector'"
|
||||
mct-object="domainObject"
|
||||
ng-model="modeModel"
|
||||
class="holder flex-elem menus-up mode-selector">
|
||||
</mct-representation>
|
||||
<mct-control
|
||||
key="'menu-button'"
|
||||
class="holder flex-elem menus-up time-system"
|
||||
structure="{
|
||||
text: timeSystemModel.selected.metadata.name,
|
||||
click: tcController.selectTimeSystem,
|
||||
options: timeSystemModel.options
|
||||
}">
|
||||
</mct-control>
|
||||
<!-- Zoom control -->
|
||||
<div class="l-time-conductor-zoom-w grows flex-elem l-flex-row">
|
||||
<span class="time-conductor-zoom-current-range flex-elem flex-fixed holder">Mars Minutes</span>
|
||||
<input class="time-conductor-zoom flex-elem" type="range" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,92 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(['./TickSource'], function (TickSource) {
|
||||
/**
|
||||
* @implements TickSource
|
||||
* @constructor
|
||||
*/
|
||||
function LocalClock ($timeout, period) {
|
||||
TickSource.call(this);
|
||||
|
||||
this.metadata = {
|
||||
key: 'real-time',
|
||||
glyph: '\u0043',
|
||||
label: 'Real-time',
|
||||
name: 'Real-time Mode',
|
||||
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'
|
||||
};
|
||||
|
||||
this.period = period;
|
||||
this.$timeout = $timeout;
|
||||
this.timeoutHandle = undefined;
|
||||
}
|
||||
|
||||
LocalClock.prototype = Object.create(TickSource.prototype);
|
||||
|
||||
LocalClock.prototype.start = function () {
|
||||
this.timeoutHandle = this.$timeout(this.tick.bind(this), this.period);
|
||||
};
|
||||
|
||||
LocalClock.prototype.stop = function () {
|
||||
if (this.timeoutHandle) {
|
||||
this.$timeout.cancel(this.timeoutHandle);
|
||||
}
|
||||
};
|
||||
|
||||
LocalClock.prototype.tick = function () {
|
||||
var now = Date.now();
|
||||
this.listeners.forEach(function (listener){
|
||||
listener(now);
|
||||
});
|
||||
this.timeoutHandle = this.$timeout(this.tick.bind(this), this.period);
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a listener for the local clock. When it ticks, the local
|
||||
* clock will provide the current local system time
|
||||
*
|
||||
* @param listener
|
||||
* @returns {function} a function for deregistering the provided listener
|
||||
*/
|
||||
LocalClock.prototype.listen = function (listener) {
|
||||
var listeners = this.listeners;
|
||||
listeners.push(listener);
|
||||
|
||||
if (listeners.length === 1){
|
||||
this.start();
|
||||
}
|
||||
|
||||
return function () {
|
||||
listeners.splice(listeners.indexOf(listener));
|
||||
if (listeners.length === 0) {
|
||||
this.stop();
|
||||
}
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
LocalClock.prototype.type = function () {
|
||||
return 'clock';
|
||||
};
|
||||
|
||||
return LocalClock;
|
||||
});
|
||||
@@ -1,78 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./TimeSystem',
|
||||
'./LocalClock'
|
||||
], function (TimeSystem, LocalClock, UTCTimeFormat) {
|
||||
var FIFTEEN_MINUTES = 15 * 60 * 1000,
|
||||
DEFAULT_PERIOD = 1000;
|
||||
|
||||
/**
|
||||
* This time system supports UTC dates and provides a ticking clock source.
|
||||
* @implements TimeSystem
|
||||
* @constructor
|
||||
*/
|
||||
function UTCTimeSystem ($timeout) {
|
||||
TimeSystem.call(this);
|
||||
|
||||
/**
|
||||
* Some metadata, which will be used to identify the time system in
|
||||
* the UI
|
||||
* @type {{key: string, name: string, glyph: string}}
|
||||
*/
|
||||
this.metadata = {
|
||||
'key': 'utc',
|
||||
'name': 'UTC',
|
||||
'glyph': '\u0043'
|
||||
};
|
||||
|
||||
//Time formats are defined as extensions. Include the key
|
||||
// for the corresponding time format here
|
||||
this._formats = ['utc'];
|
||||
this._tickSources = [new LocalClock($timeout, DEFAULT_PERIOD)];
|
||||
}
|
||||
|
||||
UTCTimeSystem.prototype = Object.create(TimeSystem.prototype);
|
||||
|
||||
UTCTimeSystem.prototype.formats = function () {
|
||||
return this._formats;
|
||||
};
|
||||
|
||||
UTCTimeSystem.prototype.tickSources = function () {
|
||||
return this._tickSources;
|
||||
};
|
||||
|
||||
UTCTimeSystem.prototype.defaults = function () {
|
||||
var now = Math.ceil(Date.now() / 1000) * 1000;
|
||||
return [
|
||||
{
|
||||
key: 'utc-default',
|
||||
name: 'UTC time system defaults',
|
||||
deltas: {start: FIFTEEN_MINUTES, end: 0},
|
||||
bounds: {start: now - FIFTEEN_MINUTES, end: now}
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
return UTCTimeSystem;
|
||||
});
|
||||
@@ -1,89 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"zepto",
|
||||
"d3"
|
||||
],
|
||||
function ($, d3) {
|
||||
|
||||
/**
|
||||
* The mct-conductor-axis renders a horizontal axis with regular
|
||||
* labelled 'ticks'. It requires 'start' and 'end' integer values to
|
||||
* be specified as attributes.
|
||||
*/
|
||||
function MCTConductorAxis(conductor) {
|
||||
|
||||
function link(scope, element, attrs, ngModelController) {
|
||||
var target = element[0].firstChild,
|
||||
height = target.offsetHeight,
|
||||
padding = 1;
|
||||
|
||||
var vis = d3.select(target)
|
||||
.append('svg:svg')
|
||||
.attr('width', '100%')
|
||||
.attr('height', height);
|
||||
var xScale = d3.scaleUtc();
|
||||
var xAxis = d3.axisTop();
|
||||
// draw x axis with labels and move to the bottom of the chart area
|
||||
var axisElement = vis.append("g")
|
||||
.attr("transform", "translate(0," + (height - padding) + ")");
|
||||
|
||||
function setScale(start, end) {
|
||||
var width = target.offsetWidth;
|
||||
xScale.domain([new Date(start), new Date(end)])
|
||||
.range([padding, width - padding * 2]);
|
||||
xAxis.scale(xScale);
|
||||
axisElement.call(xAxis);
|
||||
}
|
||||
|
||||
scope.resize = function () {
|
||||
setScale(conductor.bounds().start, conductor.bounds().end);
|
||||
};
|
||||
|
||||
//On conductor bounds changes, redraw ticks
|
||||
conductor.on('bounds', function (bounds) {
|
||||
setScale(bounds.start, bounds.end);
|
||||
});
|
||||
|
||||
//Set initial scale.
|
||||
setScale(conductor.bounds().start, conductor.bounds().end);
|
||||
}
|
||||
|
||||
return {
|
||||
// Only show at the element level
|
||||
restrict: "E",
|
||||
|
||||
template: "<div class=\"l-axis-holder\" mct-resize=\"resize()\"></div>",
|
||||
|
||||
// ngOptions is terminal, so we need to be higher priority
|
||||
priority: 1000,
|
||||
|
||||
// Link function
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTConductorAxis;
|
||||
}
|
||||
);
|
||||
@@ -1,223 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
'./modes/FixedMode',
|
||||
'./modes/RealtimeMode',
|
||||
'./modes/LADMode',
|
||||
'./TimeConductorValidation'
|
||||
],
|
||||
function (FixedMode, RealtimeMode, LADMode, TimeConductorValidation) {
|
||||
|
||||
function TimeConductorController($scope, conductor, timeSystems) {
|
||||
|
||||
var self = this;
|
||||
|
||||
//Bind all class functions to 'this'
|
||||
Object.keys(TimeConductorController.prototype).filter(function (key) {
|
||||
return typeof TimeConductorController.prototype[key] === 'function';
|
||||
}).forEach(function (key) {
|
||||
self[key] = self[key].bind(self);
|
||||
});
|
||||
|
||||
this.conductor = conductor;
|
||||
// Construct the provided time system definitions
|
||||
this.timeSystems = timeSystems.map(function (timeSystemConstructor){
|
||||
return timeSystemConstructor();
|
||||
});
|
||||
// Populate a list of modes supported by the time conductor
|
||||
this.modes = [
|
||||
new FixedMode(this.conductor, this.timeSystems),
|
||||
new RealtimeMode(this.conductor, this.timeSystems),
|
||||
new LADMode(this.conductor, this.timeSystems)
|
||||
];
|
||||
|
||||
this.validation = new TimeConductorValidation(conductor);
|
||||
this.$scope = $scope;
|
||||
this.initializeScope($scope);
|
||||
|
||||
conductor.on('bounds', this.setBounds);
|
||||
conductor.on('follow', function (follow){
|
||||
$scope.followMode = follow;
|
||||
});
|
||||
|
||||
//Set the time conductor mode to the first one in the list,
|
||||
// effectively initializing the time conductor
|
||||
this.setMode(this.modes[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
TimeConductorController.prototype.initializeScope = function ($scope) {
|
||||
$scope.timeSystemModel = {
|
||||
selected: undefined,
|
||||
format: undefined,
|
||||
options: []
|
||||
};
|
||||
$scope.modeModel = {
|
||||
selected: undefined,
|
||||
options: this.modes
|
||||
};
|
||||
$scope.formModel = {
|
||||
start: 0,
|
||||
end: 0
|
||||
};
|
||||
$scope.changing = {
|
||||
'start': false,
|
||||
'end': false
|
||||
};
|
||||
|
||||
$scope.$watch('modeModel.selected', this.setMode);
|
||||
$scope.$watch('timeSystem', this.setTimeSystem);
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
var mode = $scope.modeModel.selected;
|
||||
if (mode && mode.destroy) {
|
||||
mode.destroy();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the bounds change in the time conductor. Synchronizes
|
||||
* the bounds values in the time conductor with those in the form
|
||||
* @param bounds
|
||||
*/
|
||||
TimeConductorController.prototype.setBounds = function (bounds) {
|
||||
if (!this.$scope.changing['start']) {
|
||||
this.$scope.formModel.start = bounds.start;
|
||||
}
|
||||
if (!this.$scope.changing['end']) {
|
||||
this.$scope.formModel.end = bounds.end;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when form values are changed. Synchronizes the form with
|
||||
* the time conductor
|
||||
* @param formModel
|
||||
*/
|
||||
TimeConductorController.prototype.updateBoundsFromForm = function (formModel) {
|
||||
var newBounds = {start: formModel.start, end: formModel.end};
|
||||
|
||||
if (this.conductor.validateBounds(newBounds) === true) {
|
||||
this.conductor.bounds(newBounds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the delta values in the form change. Validates and
|
||||
* sets the new deltas on the Mode.
|
||||
* @param formModel
|
||||
* @see TimeConductorMode
|
||||
*/
|
||||
TimeConductorController.prototype.updateDeltasFromForm = function (formModel) {
|
||||
var mode = this.$scope.modeModel.selected,
|
||||
deltas = mode.deltas();
|
||||
|
||||
if (deltas !== undefined && this.validation.validateDeltas(formModel)) {
|
||||
//Sychronize deltas between form and mode
|
||||
mode.deltas({start: formModel.startDelta, end: formModel.endDelta});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the selected Time Conductor mode. This will call destroy
|
||||
* and initialization functions on the relevant modes, setting
|
||||
* default values for bound and deltas in the form.
|
||||
* @param newMode
|
||||
* @param oldMode
|
||||
*/
|
||||
TimeConductorController.prototype.setMode = function (newMode, oldMode) {
|
||||
if (newMode !== oldMode) {
|
||||
if (oldMode && oldMode.destroy) {
|
||||
oldMode.destroy();
|
||||
}
|
||||
newMode.initialize();
|
||||
|
||||
var timeSystem = newMode.selectedTimeSystem();
|
||||
|
||||
this.$scope.modeModel.selected = newMode;
|
||||
|
||||
//Synchronize scope with time system on mode
|
||||
this.$scope.timeSystemModel.options = newMode.timeSystems().map(function (timeSystem) {
|
||||
return timeSystem.metadata;
|
||||
});
|
||||
this.$scope.timeSystemModel.selected = timeSystem;
|
||||
//Use default format
|
||||
this.$scope.timeSystemModel.format = timeSystem.formats()[0];
|
||||
this.setDefaultsFromTimeSystem(newMode.selectedTimeSystem());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
TimeConductorController.prototype.setDefaultsFromTimeSystem = function (timeSystem) {
|
||||
var defaults = timeSystem.defaults()[0];
|
||||
var deltas = defaults.deltas;
|
||||
|
||||
/*
|
||||
* If the selected mode defines deltas, set them in the form
|
||||
*/
|
||||
if (deltas !== undefined) {
|
||||
this.$scope.formModel.startDelta = deltas.start;
|
||||
this.$scope.formModel.endDelta = deltas.end;
|
||||
} else {
|
||||
this.$scope.formModel.startDelta = 0;
|
||||
this.$scope.formModel.endDelta = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Allows time system to be changed by key. This supports selection
|
||||
* from the menu. Resolves a TimeSystem object and then invokes
|
||||
* TimeConductorController#setTimeSystem
|
||||
* @param key
|
||||
* @see TimeConductorController#setTimeSystem
|
||||
*/
|
||||
TimeConductorController.prototype.selectTimeSystem = function(key){
|
||||
var selected = this.timeSystems.find(function (timeSystem){
|
||||
return timeSystem.metadata.key === key;
|
||||
});
|
||||
this.setTimeSystem(selected);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the selected time system. Will populate form with the default
|
||||
* bounds and deltas defined in the selected time system.
|
||||
* @param newTimeSystem
|
||||
*/
|
||||
TimeConductorController.prototype.setTimeSystem = function (newTimeSystem) {
|
||||
if (newTimeSystem && newTimeSystem !== this.$scope.timeSystemModel.selected) {
|
||||
this.$scope.timeSystemModel.selected = newTimeSystem;
|
||||
var mode = this.$scope.modeModel.selected;
|
||||
mode.selectedTimeSystem(newTimeSystem);
|
||||
this.setDefaultsFromTimeSystem(newTimeSystem);
|
||||
}
|
||||
};
|
||||
|
||||
return TimeConductorController;
|
||||
}
|
||||
);
|
||||
@@ -1,79 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Form validation for the TimeConductorController.
|
||||
* @param conductor
|
||||
* @constructor
|
||||
*/
|
||||
function TimeConductorValidation(conductor) {
|
||||
var self = this;
|
||||
this.conductor = conductor
|
||||
|
||||
/*
|
||||
* Bind all class functions to 'this'
|
||||
*/
|
||||
Object.keys(TimeConductorValidation.prototype).filter(function (key) {
|
||||
return typeof TimeConductorValidation.prototype[key] === 'function';
|
||||
}).forEach(function (key) {
|
||||
self[key] = self[key].bind(self);
|
||||
});
|
||||
}
|
||||
|
||||
TimeConductorValidation.prototype.validateStart = function (start) {
|
||||
var bounds = this.conductor.bounds();
|
||||
return this.conductor.validateBounds({start: start, end: bounds.end}) === true;
|
||||
};
|
||||
|
||||
TimeConductorValidation.prototype.validateEnd = function (end) {
|
||||
var bounds = this.conductor.bounds();
|
||||
return this.conductor.validateBounds({start: bounds.start, end: end}) === true;
|
||||
};
|
||||
|
||||
TimeConductorValidation.prototype.validateStartDelta = function (startDelta) {
|
||||
return startDelta > 0;
|
||||
};
|
||||
|
||||
TimeConductorValidation.prototype.validateEndDelta = function (endDelta) {
|
||||
return endDelta >= 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates the delta values in the form model. Deltas are offsets
|
||||
* from a fixed point in time, and are used in follow modes as the
|
||||
* primary determinant of conductor bounds.
|
||||
* @param formModel
|
||||
* @returns {*}
|
||||
*/
|
||||
TimeConductorValidation.prototype.validateDeltas = function (formModel) {
|
||||
// Validate that start Delta is some non-zero value, and that end
|
||||
// delta is zero or positive (ie. 'now' or some time in the future).
|
||||
return this.validateStartDelta(formModel.startDelta) && this.validateEndDelta(formModel.endDelta);
|
||||
};
|
||||
|
||||
return TimeConductorValidation;
|
||||
}
|
||||
);
|
||||
@@ -1,78 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['./TimeConductorMode'],
|
||||
function (TimeConductorMode) {
|
||||
|
||||
/**
|
||||
* Handles time conductor behavior when it is in 'fixed' mode. In
|
||||
* fixed mode, the time conductor is bound by two dates and does not
|
||||
* progress.
|
||||
* @param conductor
|
||||
* @param timeSystems
|
||||
* @constructor
|
||||
*/
|
||||
function FixedMode(conductor, timeSystems) {
|
||||
var metadata = {
|
||||
key: 'fixed',
|
||||
glyph: '\ue604',
|
||||
label: 'Fixed',
|
||||
name: 'Fixed Timespan Mode',
|
||||
description: 'Query and explore data that falls between two fixed datetimes.'
|
||||
};
|
||||
|
||||
TimeConductorMode.call(this, metadata, conductor, timeSystems);
|
||||
}
|
||||
|
||||
FixedMode.prototype = Object.create(TimeConductorMode.prototype);
|
||||
|
||||
FixedMode.prototype.initialize = function () {
|
||||
TimeConductorMode.prototype.initialize.apply(this);
|
||||
this.conductor.follow(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines behavior to occur when selected time system changes. In
|
||||
* this case, sets default bounds on the time conductor.
|
||||
* @param timeSystem
|
||||
* @returns {*}
|
||||
*/
|
||||
FixedMode.prototype.selectedTimeSystem = function (timeSystem){
|
||||
TimeConductorMode.prototype.selectedTimeSystem.apply(this, arguments);
|
||||
|
||||
if (timeSystem) {
|
||||
var defaults = timeSystem.defaults()[0];
|
||||
|
||||
var bounds = {
|
||||
start: defaults.bounds.start,
|
||||
end: defaults.bounds.end
|
||||
};
|
||||
|
||||
this.conductor.timeSystem(timeSystem, bounds);
|
||||
}
|
||||
return this._selectedTimeSystem;
|
||||
};
|
||||
|
||||
return FixedMode;
|
||||
}
|
||||
);
|
||||
@@ -1,147 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['./TimeConductorMode'],
|
||||
function (TimeConductorMode) {
|
||||
|
||||
/**
|
||||
* A parent class for Realtime and LAD modes, which both advance the
|
||||
* time conductor bounds over time. The event that advances the time
|
||||
* conductor is abstracted to a TickSource. Unlike FixedMode, the
|
||||
* two 'follow' modes define 'deltas' which are offsets from a fixed
|
||||
* end point. Thus, in follow mode, the end time of the conductor is
|
||||
* the mode relevant, with both offsets defined relative to it.
|
||||
* @constructor
|
||||
*/
|
||||
function FollowMode(metadata, conductor, timeSystems) {
|
||||
TimeConductorMode.call(this, metadata, conductor, timeSystems);
|
||||
|
||||
this._deltas = undefined;
|
||||
}
|
||||
|
||||
FollowMode.prototype = Object.create(TimeConductorMode.prototype);
|
||||
|
||||
FollowMode.prototype.initialize = function () {
|
||||
TimeConductorMode.prototype.initialize.apply(this);
|
||||
this.conductor.follow(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param time
|
||||
*/
|
||||
FollowMode.prototype.tick = function (time) {
|
||||
var deltas = this.deltas();
|
||||
this.conductor.bounds({
|
||||
start: time - deltas.start,
|
||||
end: time + deltas.end
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param tickSource
|
||||
*/
|
||||
FollowMode.prototype.listenToTickSource = function () {
|
||||
if (this._selectedTimeSystem &&
|
||||
this._timeSystems[0]) {
|
||||
|
||||
var tickSource = this._timeSystems[0].tickSources()[0];
|
||||
if (tickSource) {
|
||||
this.tickSourceUnlisten = tickSource.listen(this.tick.bind(this));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* On time system change, default the bounds values in the time
|
||||
* conductor, using the deltas associated with this mode.
|
||||
* @param timeSystem
|
||||
* @returns {TimeSystem}
|
||||
*/
|
||||
FollowMode.prototype.selectedTimeSystem = function (timeSystem) {
|
||||
TimeConductorMode.prototype.selectedTimeSystem.apply(this, arguments);
|
||||
|
||||
if (timeSystem) {
|
||||
var defaults = timeSystem.defaults()[0];
|
||||
|
||||
if (arguments.length > 0) {
|
||||
var bounds = {
|
||||
start: defaults.bounds.start,
|
||||
end: defaults.bounds.end
|
||||
};
|
||||
|
||||
if (defaults.deltas) {
|
||||
bounds.start = bounds.end - defaults.deltas.start;
|
||||
bounds.end = bounds.end + defaults.deltas.end;
|
||||
this._deltas = JSON.parse(JSON.stringify(defaults.deltas));
|
||||
}
|
||||
|
||||
this.conductor.timeSystem(timeSystem, bounds);
|
||||
|
||||
this.listenToTickSource();
|
||||
}
|
||||
}
|
||||
return this._selectedTimeSystem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get or set the current value for the deltas used by this time system.
|
||||
* On change, the new deltas will be used to calculate and set the
|
||||
* bounds on the time conductor.
|
||||
* @param deltas
|
||||
* @returns {TimeSystemDeltas}
|
||||
*/
|
||||
FollowMode.prototype.deltas = function (deltas) {
|
||||
if (arguments.length !== 0) {
|
||||
var oldEnd = this.conductor.bounds().end;
|
||||
|
||||
if (this._deltas && this._deltas.end){
|
||||
//Calculate the previous 'true' end value (without delta)
|
||||
oldEnd = oldEnd - this._deltas.end;
|
||||
}
|
||||
|
||||
this._deltas = deltas;
|
||||
|
||||
var newBounds = {
|
||||
start: oldEnd - this._deltas.start,
|
||||
end: oldEnd + this._deltas.end
|
||||
};
|
||||
|
||||
this.conductor.bounds(newBounds);
|
||||
}
|
||||
return this._deltas;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop listening to tick sources
|
||||
*/
|
||||
FollowMode.prototype.destroy = function () {
|
||||
if (this.tickSourceUnlisten) {
|
||||
this.tickSourceUnlisten();
|
||||
}
|
||||
};
|
||||
|
||||
return FollowMode;
|
||||
}
|
||||
);
|
||||
@@ -1,56 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['./FollowMode'],
|
||||
function (FollowMode) {
|
||||
|
||||
/**
|
||||
* Supports the 'Latest Available Data' mode of the time conductor.
|
||||
* This is a special case of FollowMode that advances on 'data' type
|
||||
* tick sources.
|
||||
* @param conductor
|
||||
* @param timeSystems
|
||||
* @constructor
|
||||
*/
|
||||
function LADMode(conductor, timeSystems) {
|
||||
var metadata = {
|
||||
key: 'latest',
|
||||
glyph: '\u0044',
|
||||
label: 'LAD',
|
||||
name: 'LAD Mode',
|
||||
description: 'Latest Available Data mode monitors real-time streaming data as it comes in. The Time Conductor and displays will only advance when data becomes available.'
|
||||
};
|
||||
var filteredTimeSystems = timeSystems.filter(function (timeSystem){
|
||||
return timeSystem.tickSources().some(function (tickSource){
|
||||
return tickSource.type() === 'data';
|
||||
});
|
||||
});
|
||||
|
||||
FollowMode.call(this, metadata, conductor, filteredTimeSystems);
|
||||
}
|
||||
|
||||
LADMode.prototype = Object.create(FollowMode.prototype);
|
||||
|
||||
return LADMode;
|
||||
}
|
||||
);
|
||||
@@ -1,55 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['./FollowMode'],
|
||||
function (FollowMode) {
|
||||
|
||||
/**
|
||||
* Class representing the 'realtime' mode of the time conductor.
|
||||
* This is a special case of FollowMode that only supports 'clock'
|
||||
* type tick sources.
|
||||
* @param conductor
|
||||
* @param timeSystems
|
||||
* @constructor
|
||||
*/
|
||||
function RealtimeMode(conductor, timeSystems) {
|
||||
var metadata = {
|
||||
key: 'realtime',
|
||||
glyph: '\u0043',
|
||||
label: 'Real-time',
|
||||
name: 'Real-time Mode',
|
||||
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'
|
||||
};
|
||||
var filteredTimeSystems = timeSystems.filter(function (timeSystem){
|
||||
return timeSystem.tickSources().some(function (tickSource){
|
||||
return tickSource.type() === 'clock';
|
||||
});
|
||||
});
|
||||
FollowMode.call(this, metadata, conductor, filteredTimeSystems);
|
||||
}
|
||||
|
||||
RealtimeMode.prototype = Object.create(FollowMode.prototype);
|
||||
|
||||
return RealtimeMode;
|
||||
}
|
||||
);
|
||||
@@ -1,82 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Supports mode-specific time conductor behavior. This class
|
||||
* defines a parent with default behavior that specific modes are
|
||||
* expected to override.
|
||||
*
|
||||
* @interface
|
||||
* @constructor
|
||||
* @param {TimeConductorMetadata} metadata
|
||||
*/
|
||||
function TimeConductorMode(metadata, conductor, timeSystems) {
|
||||
this.metadata = metadata;
|
||||
|
||||
this.conductor = conductor;
|
||||
this._timeSystems = timeSystems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is called when mode becomes active (ie. is selected)
|
||||
*/
|
||||
TimeConductorMode.prototype.initialize = function () {
|
||||
this.selectedTimeSystem(this._timeSystems[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time systems supported by this mode. Modes are
|
||||
* expected to determine which time systems they will support by
|
||||
* filtering a provided list of all time systems.
|
||||
*
|
||||
* @returns {TimeSystem[]} The time systems supported by this mode
|
||||
*/
|
||||
TimeConductorMode.prototype.timeSystems = function () {
|
||||
return this._timeSystems;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get or set the currently selected time system
|
||||
* @param timeSystem
|
||||
* @returns {TimeSystem} the currently selected time system
|
||||
*/
|
||||
TimeConductorMode.prototype.selectedTimeSystem = function (timeSystem) {
|
||||
if (arguments.length > 0) {
|
||||
if (this._timeSystems.indexOf(timeSystem) === -1){
|
||||
throw new Error("Unsupported time system");
|
||||
} else {
|
||||
this._selectedTimeSystem = timeSystem;
|
||||
}
|
||||
}
|
||||
return this._selectedTimeSystem;
|
||||
};
|
||||
|
||||
TimeConductorMode.prototype.destroy = function () {
|
||||
};
|
||||
|
||||
return TimeConductorMode;
|
||||
}
|
||||
);
|
||||
@@ -53,7 +53,7 @@ define([
|
||||
"provides": "telemetryService",
|
||||
"implementation": ConductorTelemetryDecorator,
|
||||
"depends": [
|
||||
"timeConductor"
|
||||
"conductorService"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -34,21 +34,22 @@ define(
|
||||
* the service which exposes the global time conductor
|
||||
* @param {TelemetryService} telemetryService the decorated service
|
||||
*/
|
||||
function ConductorTelemetryDecorator(conductor, telemetryService) {
|
||||
this.conductor = conductor;
|
||||
function ConductorTelemetryDecorator(conductorService, telemetryService) {
|
||||
this.conductorService = conductorService;
|
||||
this.telemetryService = telemetryService;
|
||||
}
|
||||
|
||||
ConductorTelemetryDecorator.prototype.amendRequests = function (requests) {
|
||||
var conductor = this.conductor,
|
||||
bounds = conductor.bounds(),
|
||||
start = bounds.start,
|
||||
end = bounds.end;
|
||||
var conductor = this.conductorService.getConductor(),
|
||||
start = conductor.displayStart(),
|
||||
end = conductor.displayEnd(),
|
||||
domain = conductor.domain();
|
||||
|
||||
function amendRequest(request) {
|
||||
request = request || {};
|
||||
request.start = start;
|
||||
request.end = end;
|
||||
request.domain = domain.key;
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ define(
|
||||
'parent'
|
||||
];
|
||||
|
||||
describe("ConductorRepresenter", function () {
|
||||
xdescribe("ConductorRepresenter", function () {
|
||||
var mockThrottle,
|
||||
mockConductorService,
|
||||
mockCompile,
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
<div class="t-imagery" ng-controller="ImageryController as imagery">
|
||||
<div class="l-image-main-wrapper l-flex-col"
|
||||
<div
|
||||
class="l-image-main-wrapper"
|
||||
ng-mouseenter="showLocalControls = true;"
|
||||
ng-mouseleave="showLocalControls = false;">
|
||||
ng-mouseleave="showLocalControls = false;"
|
||||
>
|
||||
<div
|
||||
class="l-local-controls s-local-controls"
|
||||
ng-show="false && showLocalControls">
|
||||
<a class="s-btn"
|
||||
ng-show="false && showLocalControls"
|
||||
>
|
||||
<a
|
||||
class="s-btn"
|
||||
ng-click="plot.stepBackPanZoom()"
|
||||
ng-show="1"
|
||||
title="Restore previous pan/zoom">
|
||||
<span class="ui-symbol icon"><</span>
|
||||
</a>
|
||||
|
||||
<a class="s-btn"
|
||||
<a
|
||||
class="s-btn"
|
||||
ng-click="plot.unzoom()"
|
||||
ng-show="1"
|
||||
title="Reset pan/zoom">
|
||||
@@ -20,23 +25,29 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="l-image-main s-image-main flex-elem grows"
|
||||
<div
|
||||
class="l-image-main s-image-main"
|
||||
ng-class="{ paused: imagery.paused(), stale:false }"
|
||||
mct-background-image="imagery.getImageUrl()">
|
||||
mct-background-image="imagery.getImageUrl()"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="l-image-main-controlbar flex-elem l-flex-row">
|
||||
<div class="l-image-main-controlbar l-flex-row">
|
||||
<div class="left flex-elem grows">
|
||||
<a class="s-btn show-thumbs sm hidden"
|
||||
ng-click="showThumbsBubble = (showThumbsBubble)? false:true"><span class="ui-symbol icon"></span></a>
|
||||
<a
|
||||
class="s-btn show-thumbs sm hidden"
|
||||
ng-click="showThumbsBubble = (showThumbsBubble)? false:true"
|
||||
><span class="ui-symbol icon"></span></a>
|
||||
<span class="l-timezone">{{imagery.getZone()}}</span>
|
||||
<span class="l-time">{{imagery.getTime()}}</span>
|
||||
<span class="l-date">{{imagery.getDate()}}</span>
|
||||
</div>
|
||||
<div class="right flex-elem">
|
||||
<a class="s-btn pause-play"
|
||||
<a
|
||||
class="s-btn pause-play"
|
||||
ng-click="imagery.paused(!imagery.paused())"
|
||||
ng-class="{ paused: imagery.paused() }"><span class="ui-symbol icon"></span></a>
|
||||
ng-class="{ paused: imagery.paused() }"
|
||||
><span class="ui-symbol icon"></span></a>
|
||||
<a href="{{imagery.getImageUrl()}}"
|
||||
ng-if="imagery.getImageUrl()"
|
||||
target="_blank"
|
||||
@@ -47,7 +58,8 @@
|
||||
class="s-btn l-mag s-mag ui-symbol vsm"
|
||||
ng-click="clipped = false"
|
||||
ng-show="clipped === true"
|
||||
title="Not all of image is visible; click to reset."></a>
|
||||
title="Not all of image is visible; click to reset."
|
||||
></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,6 @@ define([
|
||||
"$scope",
|
||||
"telemetryFormatter",
|
||||
"telemetryHandler",
|
||||
"timeConductor",
|
||||
"throttle",
|
||||
"PLOT_FIXED_DURATION"
|
||||
]
|
||||
|
||||
@@ -65,7 +65,6 @@ define(
|
||||
$scope,
|
||||
telemetryFormatter,
|
||||
telemetryHandler,
|
||||
conductor,
|
||||
throttle,
|
||||
PLOT_FIXED_DURATION
|
||||
) {
|
||||
@@ -126,7 +125,6 @@ define(
|
||||
duration = PLOT_FIXED_DURATION;
|
||||
|
||||
updater = new PlotUpdater(handle, domain, range, duration);
|
||||
|
||||
lastDomain = domain;
|
||||
lastRange = range;
|
||||
|
||||
@@ -229,20 +227,13 @@ define(
|
||||
}
|
||||
|
||||
// Respond to a display bounds change (requery for data)
|
||||
function changeDisplayBounds(bounds) {
|
||||
//var domainAxis = $scope.axes[0];
|
||||
function changeDisplayBounds(event, bounds) {
|
||||
var domainAxis = $scope.axes[0];
|
||||
|
||||
//domainAxis.chooseOption(bounds.domain);
|
||||
//updateDomainFormat();
|
||||
domainAxis.chooseOption(bounds.domain);
|
||||
updateDomainFormat();
|
||||
setBasePanZoom(bounds);
|
||||
|
||||
// re-query historical. What do we do about ticks? Don't want
|
||||
// to do a historical re-query on every tick. Need a
|
||||
// forward-buffer I think...
|
||||
// For now, if follow mode, don't requery
|
||||
if (!conductor.follow()) {
|
||||
requery();
|
||||
}
|
||||
requery();
|
||||
}
|
||||
|
||||
this.modeOptions = new PlotModeOptions([], subPlotFactory);
|
||||
@@ -271,8 +262,7 @@ define(
|
||||
$scope.$watch('domainObject', subscribe);
|
||||
|
||||
// Respond to external bounds changes
|
||||
//$scope.$on("telemetry:display:bounds", changeDisplayBounds);
|
||||
conductor.on('bounds', changeDisplayBounds);
|
||||
$scope.$on("telemetry:display:bounds", changeDisplayBounds);
|
||||
|
||||
// Unsubscribe when the plot is destroyed
|
||||
$scope.$on("$destroy", releaseSubscription);
|
||||
|
||||
@@ -164,11 +164,9 @@ define(
|
||||
priorDomainDimensions = this.dimensions[0];
|
||||
|
||||
if (bufferArray.length > 0) {
|
||||
if (!this.domainExtrema) {
|
||||
this.domainExtrema = bufferArray.map(function (lineBuffer) {
|
||||
return lineBuffer.getDomainExtrema();
|
||||
}).reduce(reduceExtrema);
|
||||
}
|
||||
this.domainExtrema = bufferArray.map(function (lineBuffer) {
|
||||
return lineBuffer.getDomainExtrema();
|
||||
}).reduce(reduceExtrema);
|
||||
|
||||
this.rangeExtrema = bufferArray.map(function (lineBuffer) {
|
||||
return lineBuffer.getRangeExtrema();
|
||||
|
||||
@@ -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
|
||||
) {
|
||||
/**
|
||||
@@ -109,7 +115,7 @@ define([
|
||||
{
|
||||
"key": "HistoricalTableController",
|
||||
"implementation": HistoricalTableController,
|
||||
"depends": ["$scope", "telemetryHandler", "telemetryFormatter", "$timeout"]
|
||||
"depends": ["$scope", "telemetryHandler", "telemetryFormatter"]
|
||||
},
|
||||
{
|
||||
"key": "RealtimeTableController",
|
||||
@@ -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": [
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<div ng-controller="HistoricalTableController" ng-class="{'loading': loading}">
|
||||
<div ng-controller="HistoricalTableController">
|
||||
<mct-table
|
||||
headers="headers"
|
||||
rows="rows"
|
||||
enableFilter="true"
|
||||
enableSort="true"
|
||||
class="tabular-holder t-exportable">
|
||||
enableSort="true">
|
||||
</mct-table>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user