Compare commits
2 Commits
open933-fr
...
tc-api-tak
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86b3da1e86 | ||
|
|
a910b86109 |
@@ -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);
|
||||
}());
|
||||
@@ -18,8 +18,6 @@
|
||||
"node-uuid": "^1.4.7",
|
||||
"comma-separated-values": "^3.6.4",
|
||||
"FileSaver.js": "^0.0.2",
|
||||
"zepto": "^1.1.6",
|
||||
"eventemitter3": "^1.2.0",
|
||||
"d3": "~4.1.0"
|
||||
"zepto": "^1.1.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ deployment:
|
||||
test:
|
||||
post:
|
||||
- gulp lint
|
||||
- gulp checkstyle
|
||||
|
||||
general:
|
||||
branches:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,12 +45,11 @@ define(
|
||||
function buildTaxonomy(dictionary){
|
||||
var models = {};
|
||||
|
||||
function addMeasurement(measurement, parent){
|
||||
function addMeasurement(measurement){
|
||||
var format = FORMAT_MAPPINGS[measurement.type];
|
||||
models[makeId(measurement)] = {
|
||||
type: "msl.measurement",
|
||||
name: measurement.name,
|
||||
location: parent,
|
||||
telemetry: {
|
||||
key: measurement.identifier,
|
||||
ranges: [{
|
||||
@@ -63,24 +62,17 @@ define(
|
||||
};
|
||||
}
|
||||
|
||||
function addInstrument(subsystem, spacecraftId) {
|
||||
var measurements = (subsystem.measurements || []),
|
||||
instrumentId = makeId(subsystem);
|
||||
|
||||
models[instrumentId] = {
|
||||
function addInstrument(subsystem) {
|
||||
var measurements = (subsystem.measurements || []);
|
||||
models[makeId(subsystem)] = {
|
||||
type: "msl.instrument",
|
||||
name: subsystem.name,
|
||||
location: spacecraftId,
|
||||
composition: measurements.map(makeId)
|
||||
};
|
||||
measurements.forEach(function(measurement) {
|
||||
addMeasurement(measurement, instrumentId);
|
||||
});
|
||||
measurements.forEach(addMeasurement);
|
||||
}
|
||||
|
||||
(dictionary.instruments || []).forEach(function(instrument) {
|
||||
addInstrument(instrument, "msl:curiosity");
|
||||
});
|
||||
(dictionary.instruments || []).forEach(addInstrument);
|
||||
return models;
|
||||
}
|
||||
|
||||
|
||||
11
main.js
11
main.js
@@ -28,15 +28,13 @@ requirejs.config({
|
||||
"angular-route": "bower_components/angular-route/angular-route.min",
|
||||
"csv": "bower_components/comma-separated-values/csv.min",
|
||||
"es6-promise": "bower_components/es6-promise/promise.min",
|
||||
"EventEmitter": "bower_components/eventemitter3/index",
|
||||
"moment": "bower_components/moment/moment",
|
||||
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
|
||||
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
|
||||
"screenfull": "bower_components/screenfull/dist/screenfull.min",
|
||||
"text": "bower_components/text/text",
|
||||
"uuid": "bower_components/node-uuid/uuid",
|
||||
"zepto": "bower_components/zepto/zepto.min",
|
||||
"d3": "bower_components/d3/d3.min"
|
||||
"zepto": "bower_components/zepto/zepto.min"
|
||||
},
|
||||
"shim": {
|
||||
"angular": {
|
||||
@@ -45,9 +43,6 @@ requirejs.config({
|
||||
"angular-route": {
|
||||
"deps": ["angular"]
|
||||
},
|
||||
"EventEmitter": {
|
||||
"exports": "EventEmitter"
|
||||
},
|
||||
"moment-duration-format": {
|
||||
"deps": ["moment"]
|
||||
},
|
||||
@@ -56,9 +51,6 @@ requirejs.config({
|
||||
},
|
||||
"zepto": {
|
||||
"exports": "Zepto"
|
||||
},
|
||||
"d3": {
|
||||
"exports": "d3"
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -90,7 +82,6 @@ define([
|
||||
'./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',
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -24,15 +24,23 @@ define([
|
||||
"./src/BrowseController",
|
||||
"./src/PaneController",
|
||||
"./src/BrowseObjectController",
|
||||
"./src/creation/CreateMenuController",
|
||||
"./src/creation/LocatorController",
|
||||
"./src/MenuArrowController",
|
||||
"./src/navigation/NavigationService",
|
||||
"./src/creation/CreationPolicy",
|
||||
"./src/navigation/NavigateAction",
|
||||
"./src/navigation/OrphanNavigationHandler",
|
||||
"./src/windowing/NewTabAction",
|
||||
"./src/windowing/FullscreenAction",
|
||||
"./src/creation/CreateActionProvider",
|
||||
"./src/creation/AddActionProvider",
|
||||
"./src/creation/CreationService",
|
||||
"./src/windowing/WindowTitler",
|
||||
"text!./res/templates/browse.html",
|
||||
"text!./res/templates/create/locator.html",
|
||||
"text!./res/templates/browse-object.html",
|
||||
"text!./res/templates/create/create-button.html",
|
||||
"text!./res/templates/create/create-menu.html",
|
||||
"text!./res/templates/items/grid-item.html",
|
||||
"text!./res/templates/browse/object-header.html",
|
||||
"text!./res/templates/menu-arrow.html",
|
||||
@@ -45,15 +53,23 @@ define([
|
||||
BrowseController,
|
||||
PaneController,
|
||||
BrowseObjectController,
|
||||
CreateMenuController,
|
||||
LocatorController,
|
||||
MenuArrowController,
|
||||
NavigationService,
|
||||
CreationPolicy,
|
||||
NavigateAction,
|
||||
OrphanNavigationHandler,
|
||||
NewTabAction,
|
||||
FullscreenAction,
|
||||
CreateActionProvider,
|
||||
AddActionProvider,
|
||||
CreationService,
|
||||
WindowTitler,
|
||||
browseTemplate,
|
||||
locatorTemplate,
|
||||
browseObjectTemplate,
|
||||
createButtonTemplate,
|
||||
createMenuTemplate,
|
||||
gridItemTemplate,
|
||||
objectHeaderTemplate,
|
||||
menuArrowTemplate,
|
||||
@@ -93,9 +109,11 @@ define([
|
||||
"$scope",
|
||||
"$route",
|
||||
"$location",
|
||||
"$window",
|
||||
"objectService",
|
||||
"navigationService",
|
||||
"urlService",
|
||||
"policyService",
|
||||
"DEFAULT_PATH"
|
||||
]
|
||||
},
|
||||
@@ -118,6 +136,22 @@ define([
|
||||
"$route"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "CreateMenuController",
|
||||
"implementation": CreateMenuController,
|
||||
"depends": [
|
||||
"$scope"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "LocatorController",
|
||||
"implementation": LocatorController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$timeout",
|
||||
"objectService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "MenuArrowController",
|
||||
"implementation": MenuArrowController,
|
||||
@@ -126,6 +160,12 @@ define([
|
||||
]
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"key": "locator",
|
||||
"template": locatorTemplate
|
||||
}
|
||||
],
|
||||
"representations": [
|
||||
{
|
||||
"key": "view-object",
|
||||
@@ -141,6 +181,17 @@ define([
|
||||
"view"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "create-button",
|
||||
"template": createButtonTemplate
|
||||
},
|
||||
{
|
||||
"key": "create-menu",
|
||||
"template": createMenuTemplate,
|
||||
"uses": [
|
||||
"action"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "grid-item",
|
||||
"template": gridItemTemplate,
|
||||
@@ -193,15 +244,19 @@ define([
|
||||
"implementation": NavigationService
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"implementation": CreationPolicy,
|
||||
"category": "creation"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"key": "navigate",
|
||||
"implementation": NavigateAction,
|
||||
"depends": [
|
||||
"navigationService",
|
||||
"$q",
|
||||
"policyService",
|
||||
"$window"
|
||||
"$q"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -247,6 +302,42 @@ define([
|
||||
"editable": false
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"key": "CreateActionProvider",
|
||||
"provides": "actionService",
|
||||
"type": "provider",
|
||||
"implementation": CreateActionProvider,
|
||||
"depends": [
|
||||
"$q",
|
||||
"typeService",
|
||||
"navigationService",
|
||||
"policyService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "AddActionProvider",
|
||||
"provides": "actionService",
|
||||
"type": "provider",
|
||||
"implementation": AddActionProvider,
|
||||
"depends": [
|
||||
"$q",
|
||||
"typeService",
|
||||
"dialogService",
|
||||
"policyService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "CreationService",
|
||||
"provides": "creationService",
|
||||
"type": "provider",
|
||||
"implementation": CreationService,
|
||||
"depends": [
|
||||
"$q",
|
||||
"$log"
|
||||
]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"implementation": WindowTitler,
|
||||
@@ -255,14 +346,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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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...
|
||||
|
||||
@@ -43,8 +43,11 @@ define(
|
||||
* override this)
|
||||
* @param {ActionContext} context the context in which the
|
||||
* action is being performed
|
||||
* @param {NavigationService} navigationService the navigation service,
|
||||
* which handles changes in navigation. It allows the object
|
||||
* being browsed/edited to be set.
|
||||
*/
|
||||
function CreateAction(type, parent, context) {
|
||||
function CreateAction(type, parent, context, $q, navigationService) {
|
||||
this.metadata = {
|
||||
key: 'create',
|
||||
glyph: type.getGlyph(),
|
||||
@@ -53,8 +56,24 @@ define(
|
||||
description: type.getDescription(),
|
||||
context: context
|
||||
};
|
||||
|
||||
this.type = type;
|
||||
this.parent = parent;
|
||||
this.navigationService = navigationService;
|
||||
this.$q = $q;
|
||||
}
|
||||
|
||||
// Get a count of views which are not flagged as non-editable.
|
||||
function countEditableViews(domainObject) {
|
||||
var views = domainObject && domainObject.useCapability('view'),
|
||||
count = 0;
|
||||
|
||||
// A view is editable unless explicitly flagged as not
|
||||
(views || []).forEach(function (view) {
|
||||
count += (view.editable !== false) ? 1 : 0;
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,31 +82,26 @@ define(
|
||||
*/
|
||||
CreateAction.prototype.perform = function () {
|
||||
var newModel = this.type.getInitialModel(),
|
||||
newObject,
|
||||
editAction,
|
||||
editorCapability;
|
||||
|
||||
function onSave() {
|
||||
return editorCapability.save();
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
return editorCapability.cancel();
|
||||
}
|
||||
parentObject = this.navigationService.getNavigation(),
|
||||
editorCapability,
|
||||
newObject;
|
||||
|
||||
newModel.type = this.type.getKey();
|
||||
newModel.location = this.parent.getId();
|
||||
newObject = this.parent.useCapability('instantiation', newModel);
|
||||
editorCapability = newObject.hasCapability('editor') && newObject.getCapability("editor");
|
||||
newModel.location = parentObject.getId();
|
||||
newObject = parentObject.useCapability('instantiation', newModel);
|
||||
|
||||
editAction = newObject.getCapability("action").getActions("edit")[0];
|
||||
//If an edit action is available, perform it
|
||||
if (editAction) {
|
||||
return editAction.perform();
|
||||
} else if (editorCapability) {
|
||||
//otherwise, use the save action
|
||||
editorCapability = newObject.getCapability("editor");
|
||||
|
||||
if (countEditableViews(newObject) > 0 && newObject.hasCapability('composition')) {
|
||||
this.navigationService.setNavigation(newObject);
|
||||
return newObject.getCapability("action").perform("edit");
|
||||
} else {
|
||||
editorCapability.edit();
|
||||
return newObject.getCapability("action").perform("save").then(onSave, onCancel);
|
||||
return newObject.useCapability("action").perform("save").then(function () {
|
||||
return editorCapability.save();
|
||||
}, function () {
|
||||
return editorCapability.cancel();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -44,8 +44,10 @@ define(
|
||||
* introduced in this bundle), responsible for handling actual
|
||||
* object creation.
|
||||
*/
|
||||
function CreateActionProvider(typeService, policyService) {
|
||||
function CreateActionProvider($q, typeService, navigationService, policyService) {
|
||||
this.typeService = typeService;
|
||||
this.navigationService = navigationService;
|
||||
this.$q = $q;
|
||||
this.policyService = policyService;
|
||||
}
|
||||
|
||||
@@ -70,7 +72,9 @@ define(
|
||||
return new CreateAction(
|
||||
type,
|
||||
destination,
|
||||
context
|
||||
context,
|
||||
self.$q,
|
||||
self.navigationService
|
||||
);
|
||||
});
|
||||
};
|
||||
@@ -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};
|
||||
|
||||
@@ -29,10 +29,13 @@ define(
|
||||
|
||||
describe("The create action provider", function () {
|
||||
var mockTypeService,
|
||||
mockDialogService,
|
||||
mockNavigationService,
|
||||
mockPolicyService,
|
||||
mockCreationPolicy,
|
||||
mockPolicyMap = {},
|
||||
mockTypes,
|
||||
mockQ,
|
||||
provider;
|
||||
|
||||
function createMockType(name) {
|
||||
@@ -58,6 +61,14 @@ define(
|
||||
"typeService",
|
||||
["listTypes"]
|
||||
);
|
||||
mockDialogService = jasmine.createSpyObj(
|
||||
"dialogService",
|
||||
["getUserInput"]
|
||||
);
|
||||
mockNavigationService = jasmine.createSpyObj(
|
||||
"navigationService",
|
||||
["setNavigation"]
|
||||
);
|
||||
mockPolicyService = jasmine.createSpyObj(
|
||||
"policyService",
|
||||
["allow"]
|
||||
@@ -80,7 +91,9 @@ define(
|
||||
mockTypeService.listTypes.andReturn(mockTypes);
|
||||
|
||||
provider = new CreateActionProvider(
|
||||
mockQ,
|
||||
mockTypeService,
|
||||
mockNavigationService,
|
||||
mockPolicyService
|
||||
);
|
||||
});
|
||||
130
platform/commonUI/browse/test/creation/CreateActionSpec.js
Normal file
130
platform/commonUI/browse/test/creation/CreateActionSpec.js
Normal file
@@ -0,0 +1,130 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
["../../src/creation/CreateAction"],
|
||||
function (CreateAction) {
|
||||
|
||||
describe("The create action", function () {
|
||||
var mockType,
|
||||
mockParent,
|
||||
mockContext,
|
||||
mockDialogService,
|
||||
mockCreationService,
|
||||
action;
|
||||
|
||||
function mockPromise(value) {
|
||||
return {
|
||||
then: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockType = jasmine.createSpyObj(
|
||||
"type",
|
||||
[
|
||||
"getKey",
|
||||
"getGlyph",
|
||||
"getName",
|
||||
"getDescription",
|
||||
"getProperties",
|
||||
"getInitialModel"
|
||||
]
|
||||
);
|
||||
mockParent = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[
|
||||
"getId",
|
||||
"getModel",
|
||||
"getCapability"
|
||||
]
|
||||
);
|
||||
mockContext = {
|
||||
domainObject: mockParent
|
||||
};
|
||||
mockDialogService = jasmine.createSpyObj(
|
||||
"dialogService",
|
||||
["getUserInput"]
|
||||
);
|
||||
mockCreationService = jasmine.createSpyObj(
|
||||
"creationService",
|
||||
["createObject"]
|
||||
);
|
||||
|
||||
mockType.getKey.andReturn("test");
|
||||
mockType.getGlyph.andReturn("T");
|
||||
mockType.getDescription.andReturn("a test type");
|
||||
mockType.getName.andReturn("Test");
|
||||
mockType.getProperties.andReturn([]);
|
||||
mockType.getInitialModel.andReturn({});
|
||||
|
||||
mockDialogService.getUserInput.andReturn(mockPromise({}));
|
||||
|
||||
action = new CreateAction(
|
||||
mockType,
|
||||
mockParent,
|
||||
mockContext,
|
||||
mockDialogService,
|
||||
mockCreationService
|
||||
);
|
||||
});
|
||||
|
||||
it("exposes type-appropriate metadata", function () {
|
||||
var metadata = action.getMetadata();
|
||||
|
||||
expect(metadata.name).toEqual("Test");
|
||||
expect(metadata.description).toEqual("a test type");
|
||||
expect(metadata.glyph).toEqual("T");
|
||||
});
|
||||
|
||||
//TODO: Disabled for NEM Beta
|
||||
xit("invokes the creation service when performed", function () {
|
||||
action.perform();
|
||||
expect(mockCreationService.createObject).toHaveBeenCalledWith(
|
||||
{ type: "test" },
|
||||
mockParent
|
||||
);
|
||||
});
|
||||
|
||||
//TODO: Disabled for NEM Beta
|
||||
xit("does not create an object if the user cancels", function () {
|
||||
mockDialogService.getUserInput.andReturn({
|
||||
then: function (callback, fail) {
|
||||
fail();
|
||||
}
|
||||
});
|
||||
|
||||
action.perform();
|
||||
|
||||
expect(mockCreationService.createObject)
|
||||
.not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,15 +43,6 @@ define([
|
||||
"./src/capabilities/EditorCapability",
|
||||
"./src/capabilities/TransactionCapabilityDecorator",
|
||||
"./src/services/TransactionService",
|
||||
"./src/creation/CreateMenuController",
|
||||
"./src/creation/LocatorController",
|
||||
"./src/creation/CreationPolicy",
|
||||
"./src/creation/CreateActionProvider",
|
||||
"./src/creation/AddActionProvider",
|
||||
"./src/creation/CreationService",
|
||||
"text!./res/templates/create/locator.html",
|
||||
"text!./res/templates/create/create-button.html",
|
||||
"text!./res/templates/create/create-menu.html",
|
||||
"text!./res/templates/library.html",
|
||||
"text!./res/templates/edit-object.html",
|
||||
"text!./res/templates/edit-action-buttons.html",
|
||||
@@ -81,15 +72,6 @@ define([
|
||||
EditorCapability,
|
||||
TransactionCapabilityDecorator,
|
||||
TransactionService,
|
||||
CreateMenuController,
|
||||
LocatorController,
|
||||
CreationPolicy,
|
||||
CreateActionProvider,
|
||||
AddActionProvider,
|
||||
CreationService,
|
||||
locatorTemplate,
|
||||
createButtonTemplate,
|
||||
createMenuTemplate,
|
||||
libraryTemplate,
|
||||
editObjectTemplate,
|
||||
editActionButtonsTemplate,
|
||||
@@ -130,22 +112,6 @@ define([
|
||||
"$location",
|
||||
"policyService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "CreateMenuController",
|
||||
"implementation": CreateMenuController,
|
||||
"depends": [
|
||||
"$scope"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "LocatorController",
|
||||
"implementation": LocatorController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$timeout",
|
||||
"objectService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
@@ -170,7 +136,7 @@ define([
|
||||
"navigationService",
|
||||
"$log"
|
||||
],
|
||||
"description": "Edit",
|
||||
"description": "Edit this object.",
|
||||
"category": "view-control",
|
||||
"glyph": "p"
|
||||
},
|
||||
@@ -206,9 +172,7 @@ define([
|
||||
"implementation": SaveAction,
|
||||
"name": "Save",
|
||||
"description": "Save changes made to these objects.",
|
||||
"depends": [
|
||||
"dialogService"
|
||||
],
|
||||
"depends": [],
|
||||
"priority": "mandatory"
|
||||
},
|
||||
{
|
||||
@@ -255,13 +219,10 @@ define([
|
||||
},
|
||||
{
|
||||
"category": "navigation",
|
||||
"message": "Continuing will cause the loss of any unsaved changes.",
|
||||
"message": "There are unsaved changes.",
|
||||
"implementation": EditNavigationPolicy
|
||||
},
|
||||
{
|
||||
"implementation": CreationPolicy,
|
||||
"category": "creation"
|
||||
}
|
||||
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
@@ -300,17 +261,6 @@ define([
|
||||
{
|
||||
"key": "topbar-edit",
|
||||
"template": topbarEditTemplate
|
||||
},
|
||||
{
|
||||
"key": "create-button",
|
||||
"template": createButtonTemplate
|
||||
},
|
||||
{
|
||||
"key": "create-menu",
|
||||
"template": createMenuTemplate,
|
||||
"uses": [
|
||||
"action"
|
||||
]
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
@@ -332,40 +282,7 @@ define([
|
||||
"$q",
|
||||
"$log"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "CreateActionProvider",
|
||||
"provides": "actionService",
|
||||
"type": "provider",
|
||||
"implementation": CreateActionProvider,
|
||||
"depends": [
|
||||
"typeService",
|
||||
"policyService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "AddActionProvider",
|
||||
"provides": "actionService",
|
||||
"type": "provider",
|
||||
"implementation": AddActionProvider,
|
||||
"depends": [
|
||||
"$q",
|
||||
"typeService",
|
||||
"dialogService",
|
||||
"policyService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "CreationService",
|
||||
"provides": "creationService",
|
||||
"type": "provider",
|
||||
"implementation": CreationService,
|
||||
"depends": [
|
||||
"$q",
|
||||
"$log"
|
||||
]
|
||||
}
|
||||
|
||||
],
|
||||
"representers": [
|
||||
{
|
||||
@@ -399,12 +316,6 @@ define([
|
||||
"transactionService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"key": "locator",
|
||||
"template": locatorTemplate
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,12 +74,6 @@ define(
|
||||
self.domainObject.getCapability('editor').cancel();
|
||||
self.navigationService.removeListener(cancelEditing);
|
||||
}
|
||||
//If this is not the currently navigated object, then navigate
|
||||
// to it.
|
||||
if (this.navigationService.getNavigation() !== this.domainObject) {
|
||||
this.navigationService.setNavigation(this.domainObject);
|
||||
}
|
||||
|
||||
this.navigationService.addListener(cancelEditing);
|
||||
this.domainObject.useCapability("editor");
|
||||
};
|
||||
|
||||
@@ -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(
|
||||
['../../../browse/src/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()) {
|
||||
|
||||
@@ -56,10 +56,7 @@ define(
|
||||
// A view is editable unless explicitly flagged as not
|
||||
(views || []).forEach(function (view) {
|
||||
if (view.editable === true ||
|
||||
(view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
|
||||
(view.key === 'table' && type.getKey() === 'table') ||
|
||||
(view.key === 'rt-table' && type.getKey() === 'rttable')
|
||||
) {
|
||||
(view.key === 'plot' && type.getKey() === 'telemetry.panel')) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,190 +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.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
["../../src/creation/CreateAction"],
|
||||
function (CreateAction) {
|
||||
|
||||
describe("The create action", function () {
|
||||
var mockType,
|
||||
mockParent,
|
||||
mockContext,
|
||||
mockDomainObject,
|
||||
capabilities = {},
|
||||
mockEditAction,
|
||||
mockSaveAction,
|
||||
action;
|
||||
|
||||
function mockPromise(value) {
|
||||
return {
|
||||
then: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockType = jasmine.createSpyObj(
|
||||
"type",
|
||||
[
|
||||
"getKey",
|
||||
"getGlyph",
|
||||
"getName",
|
||||
"getDescription",
|
||||
"getProperties",
|
||||
"getInitialModel"
|
||||
]
|
||||
);
|
||||
mockParent = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[
|
||||
"getId",
|
||||
"getModel",
|
||||
"getCapability",
|
||||
"useCapability"
|
||||
]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[
|
||||
"getId",
|
||||
"getModel",
|
||||
"getCapability",
|
||||
"hasCapability",
|
||||
"useCapability"
|
||||
]
|
||||
);
|
||||
mockDomainObject.hasCapability.andCallFake(function (name) {
|
||||
return !!capabilities[name];
|
||||
});
|
||||
mockDomainObject.getCapability.andCallFake(function (name) {
|
||||
return capabilities[name];
|
||||
});
|
||||
mockSaveAction = jasmine.createSpyObj(
|
||||
"saveAction",
|
||||
[
|
||||
"perform"
|
||||
]
|
||||
);
|
||||
|
||||
capabilities.action = jasmine.createSpyObj(
|
||||
"actionCapability",
|
||||
[
|
||||
"getActions",
|
||||
"perform"
|
||||
]
|
||||
);
|
||||
|
||||
capabilities.editor = jasmine.createSpyObj(
|
||||
"editorCapability",
|
||||
[
|
||||
"edit",
|
||||
"save",
|
||||
"cancel"
|
||||
]
|
||||
);
|
||||
|
||||
mockEditAction = jasmine.createSpyObj(
|
||||
"editAction",
|
||||
[
|
||||
"perform"
|
||||
]
|
||||
);
|
||||
|
||||
mockContext = {
|
||||
domainObject: mockParent
|
||||
};
|
||||
mockParent.useCapability.andReturn(mockDomainObject);
|
||||
|
||||
mockType.getKey.andReturn("test");
|
||||
mockType.getGlyph.andReturn("T");
|
||||
mockType.getDescription.andReturn("a test type");
|
||||
mockType.getName.andReturn("Test");
|
||||
mockType.getProperties.andReturn([]);
|
||||
mockType.getInitialModel.andReturn({});
|
||||
|
||||
action = new CreateAction(
|
||||
mockType,
|
||||
mockParent,
|
||||
mockContext
|
||||
);
|
||||
});
|
||||
|
||||
it("exposes type-appropriate metadata", function () {
|
||||
var metadata = action.getMetadata();
|
||||
|
||||
expect(metadata.name).toEqual("Test");
|
||||
expect(metadata.description).toEqual("a test type");
|
||||
expect(metadata.glyph).toEqual("T");
|
||||
});
|
||||
|
||||
describe("the perform function", function () {
|
||||
beforeEach(function () {
|
||||
capabilities.action.getActions.andReturn([mockEditAction]);
|
||||
});
|
||||
|
||||
it("uses the instantiation capability when performed", function () {
|
||||
action.perform();
|
||||
expect(mockParent.useCapability).toHaveBeenCalledWith("instantiation", jasmine.any(Object));
|
||||
});
|
||||
|
||||
it("uses the edit action if available", function () {
|
||||
action.perform();
|
||||
expect(mockEditAction.perform).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses the save action if object does not have an edit action" +
|
||||
" available", function () {
|
||||
capabilities.action.getActions.andReturn([]);
|
||||
capabilities.action.perform.andReturn(mockPromise(undefined));
|
||||
action.perform();
|
||||
expect(capabilities.action.perform).toHaveBeenCalledWith("save");
|
||||
});
|
||||
|
||||
describe("uses to editor capability", function () {
|
||||
var promise = jasmine.createSpyObj("promise", ["then"]);
|
||||
beforeEach(function () {
|
||||
capabilities.action.getActions.andReturn([]);
|
||||
capabilities.action.perform.andReturn(promise);
|
||||
});
|
||||
|
||||
it("to save the edit if user saves dialog", function () {
|
||||
action.perform();
|
||||
expect(promise.then).toHaveBeenCalled();
|
||||
promise.then.mostRecentCall.args[0]();
|
||||
expect(capabilities.editor.save).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("to cancel the edit if user cancels dialog", function () {
|
||||
action.perform();
|
||||
promise.then.mostRecentCall.args[1]();
|
||||
expect(capabilities.editor.cancel).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -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": [
|
||||
|
||||
@@ -204,7 +204,6 @@ define([
|
||||
"implementation": TimeRangeController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$timeout",
|
||||
"formatService",
|
||||
"DEFAULT_TIME_FORMAT",
|
||||
"now"
|
||||
|
||||
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; }
|
||||
}
|
||||
@@ -149,8 +145,3 @@
|
||||
.flex-justify-end {
|
||||
@include justify-content(flex-end);
|
||||
}
|
||||
|
||||
/********************************************* POPUPS */
|
||||
.t-popup {
|
||||
z-index: 75;
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ $uePaneMiniTabW: 10px;
|
||||
$uePaneMiniTabCollapsedW: 11px;
|
||||
$ueEditLeftPaneW: 75%;
|
||||
$treeSearchInputBarH: 25px;
|
||||
$ueTimeControlH: (25px, 6px, 20px);
|
||||
/*************** Panes */
|
||||
$ueTimeControlH: (33px, 20px, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,10 +63,9 @@ input, textarea {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="search"] {
|
||||
input[type="text"] {
|
||||
vertical-align: baseline;
|
||||
padding: $inputTextP;
|
||||
padding: 3px 5px !important;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
@@ -139,17 +139,6 @@
|
||||
background-size: $d $d;
|
||||
}
|
||||
|
||||
@mixin bgStripes($c: yellow, $a: 0.1, $bgsize: 5px, $angle: 90deg) {
|
||||
@include background-image(linear-gradient($angle,
|
||||
rgba($c, $a) 25%, transparent 25%,
|
||||
transparent 50%, rgba($c, $a) 50%,
|
||||
rgba($c, $a) 75%, transparent 75%,
|
||||
transparent 100%
|
||||
));
|
||||
background-repeat: repeat;
|
||||
background-size: $bgsize $bgsize;
|
||||
}
|
||||
|
||||
@mixin bgVertStripes($c: yellow, $a: 0.1, $d: 40px) {
|
||||
@include background-image(linear-gradient(-90deg,
|
||||
rgba($c, $a) 0%, rgba($c, $a) 50%,
|
||||
@@ -185,15 +174,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 +294,7 @@
|
||||
border-radius: $controlCr;
|
||||
box-sizing: border-box;
|
||||
color: $fg;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@mixin btnBase($bg: $colorBodyBg, $bgHovColor: none, $fg: $colorBodyFg, $ic: $colorBtnIcon) {
|
||||
@@ -326,13 +322,13 @@
|
||||
color: $fg;
|
||||
outline: none;
|
||||
&.error {
|
||||
background-color: $colorFormFieldErrorBg;
|
||||
color: $colorFormFieldErrorFg;
|
||||
background: rgba(red, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg) {
|
||||
@include input-base($bg, $fg);
|
||||
padding: 0 $interiorMarginSm;
|
||||
}
|
||||
|
||||
@mixin contextArrow() {
|
||||
@@ -341,6 +337,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
.accordion-head {
|
||||
$op: 0.2;
|
||||
border-radius: $basicCr * 0.75;
|
||||
box-sizing: border-box;
|
||||
box-sizing: "border-box";
|
||||
background: rgba($colorBodyFg, $op);
|
||||
cursor: pointer;
|
||||
font-size: 0.75em;
|
||||
@@ -396,11 +396,11 @@ input[type="search"] {
|
||||
left: auto;
|
||||
}
|
||||
.knob-l {
|
||||
@include border-left-radius($sliderKnobR);
|
||||
@include border-left-radius($sliderKnobW);
|
||||
cursor: w-resize;
|
||||
}
|
||||
.knob-r {
|
||||
@include border-right-radius($sliderKnobR);
|
||||
@include border-right-radius($sliderKnobW);
|
||||
cursor: e-resize;
|
||||
}
|
||||
.range {
|
||||
@@ -420,69 +420,13 @@ 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;
|
||||
@include user-select(none);
|
||||
font-size: 0.8rem;
|
||||
padding: $interiorMarginLg !important;
|
||||
width: 230px;
|
||||
.l-month-year-pager {
|
||||
$pagerW: 20px;
|
||||
height: $r1H;
|
||||
@@ -574,19 +518,6 @@ input[type="range"] {
|
||||
}
|
||||
}
|
||||
|
||||
@include phone {
|
||||
.l-datetime-picker {
|
||||
padding: $interiorMargin !important;
|
||||
}
|
||||
.l-calendar {
|
||||
ul.l-cal-row {
|
||||
li {
|
||||
padding: 2px $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** TEXTAREA */
|
||||
textarea {
|
||||
@include nice-textarea($colorInputBg, $colorInputFg);
|
||||
|
||||
@@ -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,354 @@
|
||||
@mixin toiLineHovEffects() {
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: $timeControllerToiLineColorHov;
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-controller {
|
||||
$minW: 500px;
|
||||
$knobHOffset: 0px;
|
||||
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
||||
$rangeValPad: $interiorMargin;
|
||||
$rangeValOffset: $sliderKnobW;
|
||||
$timeRangeSliderLROffset: 130px + $sliderKnobW + $rangeValOffset;
|
||||
$r1H: nth($ueTimeControlH,1);
|
||||
$r2H: nth($ueTimeControlH,2);
|
||||
$r3H: nth($ueTimeControlH,3);
|
||||
|
||||
display: block;
|
||||
height: $r1H + $r2H + $r3H + ($interiorMargin * 2);
|
||||
min-width: $minW;
|
||||
font-size: 0.8rem;
|
||||
|
||||
|
||||
.l-time-range-inputs-holder,
|
||||
.l-time-range-slider-holder,
|
||||
.l-time-range-ticks-holder
|
||||
{
|
||||
@include absPosDefault(0, visible);
|
||||
box-sizing: border-box;
|
||||
top: auto;
|
||||
}
|
||||
.l-time-range-slider,
|
||||
.l-time-range-ticks {
|
||||
@include absPosDefault(0, visible);
|
||||
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
height: $r1H; bottom: $r2H + $r3H + ($interiorMarginSm * 2);
|
||||
padding-top: $interiorMargin;
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
.type-icon {
|
||||
font-size: 120%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.l-time-range-input,
|
||||
.l-time-range-inputs-elem {
|
||||
margin-right: $interiorMargin;
|
||||
.lbl {
|
||||
color: $colorPlotLabelFg;
|
||||
}
|
||||
.ui-symbol.icon {
|
||||
font-size: 11px;
|
||||
width: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-slider-holder {
|
||||
height: $r2H; bottom: $r3H + ($interiorMarginSm * 1);
|
||||
.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,
|
||||
&:after {
|
||||
background-color: $myC;
|
||||
content: "";
|
||||
position: absolute;
|
||||
}
|
||||
&:before {
|
||||
// Vert line
|
||||
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
||||
width: 2px;
|
||||
}
|
||||
&:after {
|
||||
// Circle element
|
||||
border-radius: $myW;
|
||||
@include transform(translateY(-50%));
|
||||
top: 50%; right: 0; bottom: auto; left: 0;
|
||||
width: auto;
|
||||
height: $myW;
|
||||
}
|
||||
}
|
||||
&: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.9em;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
white-space: nowrap;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.knob {
|
||||
z-index: 2;
|
||||
.range-value {
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
padding: 0 $rangeValOffset;
|
||||
position: absolute;
|
||||
height: $r2H;
|
||||
line-height: $r2H;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&: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;
|
||||
bottom: 46px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.s-time-range-val {
|
||||
border-radius: $controlCr;
|
||||
background-color: $colorInputBg;
|
||||
padding: 1px 1px 0 $interiorMargin;
|
||||
}
|
||||
|
||||
@include phoneandtablet {
|
||||
.l-time-controller, .l-time-range-inputs-holder {
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.l-time-controller {
|
||||
|
||||
.l-time-domain-selector {
|
||||
select {
|
||||
height: 25px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-slider-holder, .l-time-range-ticks-holder {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.time-range-start, .time-range-end, {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
.l-time-range-input {
|
||||
display: block;
|
||||
.s-btn {
|
||||
padding-right: 18px;
|
||||
white-space: nowrap;
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.l-time-range-inputs-elem {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include phone {
|
||||
.l-time-controller {
|
||||
height: 48px;
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
bottom: 24px;
|
||||
}
|
||||
|
||||
.l-time-domain-selector {
|
||||
width: 33%;
|
||||
bottom: -9px;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
.l-time-range-input {
|
||||
margin-bottom: 5px;
|
||||
.s-btn {
|
||||
width: 66%;
|
||||
}
|
||||
}
|
||||
.l-time-range-inputs-elem {
|
||||
&.ui-symbol {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.lbl {
|
||||
width: 33%;
|
||||
right: 0px;
|
||||
top: 5px;
|
||||
display: block;
|
||||
height: 25px;
|
||||
margin: 0;
|
||||
line-height: 25px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include tablet {
|
||||
.l-time-controller {
|
||||
height: 17px;
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
bottom: -7px;
|
||||
left: -5px;
|
||||
}
|
||||
|
||||
.l-time-domain-selector {
|
||||
width: 23%;
|
||||
right: -4px;
|
||||
bottom: -10px;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
.l-time-range-input {
|
||||
float: left;
|
||||
.s-btn {
|
||||
width: 100%;
|
||||
padding-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include tabletLandscape {
|
||||
.l-time-controller {
|
||||
height: 17px;
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
bottom: -7px;
|
||||
}
|
||||
|
||||
.l-time-domain-selector {
|
||||
width: 23%;
|
||||
right: auto;
|
||||
bottom: -10px;
|
||||
left: 391px;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
.l-time-range-inputs-elem {
|
||||
&.ui-symbol, &.lbl {
|
||||
display: block;
|
||||
float: left;
|
||||
line-height: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pane-tree-hidden .l-time-controller {
|
||||
.l-time-domain-selector {
|
||||
left: 667px;
|
||||
}
|
||||
.l-time-range-inputs-holder {
|
||||
padding-left: 277px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include tabletPortrait {
|
||||
.l-time-controller {
|
||||
height: 17px;
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
bottom: -7px;
|
||||
left: -5px;
|
||||
}
|
||||
|
||||
.l-time-domain-selector {
|
||||
width: 23%;
|
||||
right: -4px;
|
||||
bottom: -10px;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
.l-time-range-input {
|
||||
width: 38%;
|
||||
float: left;
|
||||
}
|
||||
.l-time-range-inputs-elem {
|
||||
&.ui-symbol, &.lbl {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -196,7 +194,7 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
|
||||
.holder.holder-treeview-elements {
|
||||
top: $bodyMargin;
|
||||
right: 0;
|
||||
bottom: $interiorMargin;
|
||||
bottom: $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
.create-btn-holder {
|
||||
&.s-status-editing {
|
||||
@@ -217,17 +215,17 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
|
||||
left: 0;
|
||||
.holder-object {
|
||||
top: $bodyMargin;
|
||||
bottom: $interiorMargin;
|
||||
bottom: $bodyMargin;
|
||||
}
|
||||
.holder-inspector {
|
||||
top: $bodyMargin;
|
||||
bottom: $interiorMargin;
|
||||
bottom: $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
right: $bodyMargin;
|
||||
}
|
||||
.holder-elements {
|
||||
top: 0;
|
||||
bottom: $interiorMargin;
|
||||
bottom: $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
right: $bodyMargin;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,28 +19,27 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span ng-controller="DateTimeFieldController">
|
||||
<span class="s-btn"
|
||||
ng-controller="DateTimeFieldController">
|
||||
<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
|
||||
!structure.validate(ngModel[field]))
|
||||
}">
|
||||
</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>
|
||||
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'"
|
||||
ng-model="pickerModel"
|
||||
field="'value'">
|
||||
field="'value'"
|
||||
options="{ hours: true }">
|
||||
</mct-control>
|
||||
</div>
|
||||
</mct-popup>
|
||||
|
||||
@@ -19,43 +19,42 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
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"
|
||||
<div ng-controller="TimeRangeController as trCtrl">
|
||||
<form class="l-time-range-inputs-holder"
|
||||
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-input-w flex-elem">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: parameters.format,
|
||||
validate: trCtrl.validateStart
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-blur="trCtrl.updateBoundsFromForm()"
|
||||
field="'start'"
|
||||
class="time-range-start">
|
||||
</mct-control>
|
||||
</span>
|
||||
|
||||
<span class="l-time-range-inputs-elem lbl flex-elem">to</span>
|
||||
|
||||
<span class="l-time-range-input-w flex-elem" ng-controller="ToggleController as t2">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: parameters.format,
|
||||
validate: trCtrl.validateEnd
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-blur="trCtrl.updateBoundsFromForm()"
|
||||
field="'end'"
|
||||
class="time-range-end">
|
||||
</mct-control>
|
||||
</span>
|
||||
<span class="l-time-range-inputs-elem ui-symbol type-icon">C</span>
|
||||
<span class="l-time-range-input">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: parameters.format,
|
||||
validate: trCtrl.validateStart
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-blur="trCtrl.updateBoundsFromForm()"
|
||||
field="'start'"
|
||||
class="time-range-start">
|
||||
</mct-control>
|
||||
</span>
|
||||
|
||||
<span class="l-time-range-inputs-elem lbl">to</span>
|
||||
|
||||
<span class="l-time-range-input" ng-controller="ToggleController as t2">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{
|
||||
format: parameters.format,
|
||||
validate: trCtrl.validateEnd
|
||||
}"
|
||||
ng-model="formModel"
|
||||
ng-blur="trCtrl.updateBoundsFromForm()"
|
||||
field="'end'"
|
||||
class="time-range-end">
|
||||
</mct-control>
|
||||
</span>
|
||||
|
||||
<input type="submit" class="hidden">
|
||||
</form>
|
||||
|
||||
<div class="l-time-range-slider-holder flex-elem">
|
||||
<div class="l-time-range-slider-holder">
|
||||
<div class="l-time-range-slider">
|
||||
<div class="slider"
|
||||
mct-resize="spanWidth = bounds.width">
|
||||
@@ -86,7 +85,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="l-time-conductor-ticks flex-elem">
|
||||
<div class="l-time-range-ticks-holder">
|
||||
<div class="l-time-range-ticks">
|
||||
<div
|
||||
ng-repeat="tick in ticks track by $index"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,10 @@ define(
|
||||
position = [rect.left, rect.top],
|
||||
popup = popupService.display(div, position);
|
||||
|
||||
div.addClass('t-popup');
|
||||
// TODO: Handle in CSS;
|
||||
// https://github.com/nasa/openmctweb/issues/298
|
||||
div.css('z-index', 75);
|
||||
|
||||
transclude(function (clone) {
|
||||
div.append(clone);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -24,15 +24,7 @@ define(
|
||||
["../../src/directives/MCTPopup"],
|
||||
function (MCTPopup) {
|
||||
|
||||
var JQLITE_METHODS = [
|
||||
"on",
|
||||
"off",
|
||||
"find",
|
||||
"parent",
|
||||
"css",
|
||||
"addClass",
|
||||
"append"
|
||||
];
|
||||
var JQLITE_METHODS = ["on", "off", "find", "parent", "css", "append"];
|
||||
|
||||
describe("The mct-popup directive", function () {
|
||||
var mockCompile,
|
||||
|
||||
@@ -38,6 +38,7 @@ define(
|
||||
function InfoGestureButton($document, agentService, infoService, element, domainObject) {
|
||||
var dismissBubble,
|
||||
touchPosition,
|
||||
scopeOff,
|
||||
body = $document.find('body');
|
||||
|
||||
function trackPosition(event) {
|
||||
@@ -93,6 +94,10 @@ define(
|
||||
element.on('click', showBubble);
|
||||
}
|
||||
|
||||
// Also make sure we dismiss bubble if representation is destroyed
|
||||
// before the mouse actually leaves it
|
||||
scopeOff = element.scope().$on('$destroy', hideBubble);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Detach any event handlers associated with this gesture.
|
||||
@@ -104,6 +109,7 @@ define(
|
||||
hideBubble();
|
||||
// ...and detach listeners
|
||||
element.off('click', showBubble);
|
||||
scopeOff();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -137,11 +137,6 @@ define(
|
||||
);
|
||||
});
|
||||
|
||||
// https://github.com/nasa/openmct/issues/948
|
||||
it("does not try to access scope", function () {
|
||||
expect(mockElement.scope).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -14,7 +14,7 @@ $colorAHov: #fff;
|
||||
$contrastRatioPercent: 7%;
|
||||
$hoverRatioPercent: 10%;
|
||||
$basicCr: 3px;
|
||||
$controlCr: 2px;
|
||||
$controlCr: 3px;
|
||||
$smallCr: 2px;
|
||||
|
||||
// Buttons and Controls
|
||||
@@ -32,12 +32,11 @@ $sliderColorBase: $colorKey;
|
||||
$sliderColorRangeHolder: rgba(black, 0.1);
|
||||
$sliderColorRange: rgba($sliderColorBase, 0.3);
|
||||
$sliderColorRangeHov: rgba($sliderColorBase, 0.5);
|
||||
$sliderColorKnob: $sliderColorBase;
|
||||
$sliderColorKnobHov: pullForward($sliderColorKnob, $ltGamma);
|
||||
$sliderColorKnob: rgba($sliderColorBase, 0.6);
|
||||
$sliderColorKnobHov: $sliderColorBase;
|
||||
$sliderColorRangeValHovBg: rgba($sliderColorBase, 0.1);
|
||||
$sliderColorRangeValHovFg: $colorKeyFg;
|
||||
$sliderKnobW: 15px;
|
||||
$sliderKnobR: 2px;
|
||||
$sliderKnobW: nth($ueTimeControlH,2)/2;
|
||||
$timeControllerToiLineColor: #00c2ff;
|
||||
$timeControllerToiLineColorHov: #fff;
|
||||
|
||||
@@ -52,7 +51,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%);
|
||||
@@ -70,10 +69,8 @@ $colorCreateMenuText: $colorMenuFg;
|
||||
$colorCheck: $colorKey;
|
||||
$colorFormRequired: $colorAlt1;
|
||||
$colorFormValid: #33cc33;
|
||||
$colorFormError: #990000;
|
||||
$colorFormError: #cc0000;
|
||||
$colorFormInvalid: #ff3300;
|
||||
$colorFormFieldErrorBg: $colorFormError;
|
||||
$colorFormFieldErrorFg: rgba(#fff, 0.6);
|
||||
$colorFormLines: rgba(#fff, 0.1);
|
||||
$colorFormSectionHeader: rgba(#fff, 0.1);
|
||||
$colorInputBg: rgba(#000, 0.1);
|
||||
@@ -183,13 +180,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 +203,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);
|
||||
@@ -32,12 +32,11 @@ $sliderColorBase: $colorKey;
|
||||
$sliderColorRangeHolder: rgba(black, 0.07);
|
||||
$sliderColorRange: rgba($sliderColorBase, 0.2);
|
||||
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
|
||||
$sliderColorKnob: pushBack($sliderColorBase, 20%);
|
||||
$sliderColorKnob: rgba($sliderColorBase, 0.5);
|
||||
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
|
||||
$sliderColorRangeValHovBg: $sliderColorRange;
|
||||
$sliderColorRangeValHovBg: $sliderColorRange; //rgba($sliderColorBase, 0.1);
|
||||
$sliderColorRangeValHovFg: $colorBodyFg;
|
||||
$sliderKnobW: 15px;
|
||||
$sliderKnobR: 2px;
|
||||
$sliderKnobW: nth($ueTimeControlH,2)/2;
|
||||
$timeControllerToiLineColor: $colorBodyFg;
|
||||
$timeControllerToiLineColorHov: #0052b5;
|
||||
|
||||
@@ -52,7 +51,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%);
|
||||
@@ -70,10 +69,8 @@ $colorCreateMenuText: $colorBodyFg;
|
||||
$colorCheck: $colorKey;
|
||||
$colorFormRequired: $colorKey;
|
||||
$colorFormValid: #33cc33;
|
||||
$colorFormError: #990000;
|
||||
$colorFormError: #cc0000;
|
||||
$colorFormInvalid: #ff2200;
|
||||
$colorFormFieldErrorBg: $colorFormError;
|
||||
$colorFormFieldErrorFg: rgba(#fff, 0.6);
|
||||
$colorFormLines: rgba(#000, 0.1);
|
||||
$colorFormSectionHeader: rgba(#000, 0.05);
|
||||
$colorInputBg: $colorGenBg;
|
||||
@@ -183,13 +180,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 +204,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
150
platform/features/conductor-redux/src/README.md
Normal file
150
platform/features/conductor-redux/src/README.md
Normal file
@@ -0,0 +1,150 @@
|
||||
## Notes
|
||||
API is notional for now, based on use-cases identified below. Possible the
|
||||
use cases are not sufficient, so please include in comments
|
||||
any other use cases you'd like to see.
|
||||
|
||||
Plan now is to start building out test suite for the use cases identified below
|
||||
in order to get the API functional. Need to discuss how UI aspects of timeline will be implemented.
|
||||
Propose in place refactoring of existing timeline rather than starting again.
|
||||
|
||||
Some caveats / open questions
|
||||
* I don't understand the use case shown on page 52 of UI sketches. It shows RT/FT, with deltas,
|
||||
with inner interval unlocked. Not sure what result would be, has inner end switched to fixed?
|
||||
Also example on page 55 in real-time where inner end < now. Is there a use case for this? Semantically, it's saying
|
||||
show me real time, but stale data. Why would a user want this? My feeling is that if the inner
|
||||
OR outer ends are moved behind NOW in real-time mode then you drop into historical mode.
|
||||
* For the API itself, have ignored question of how it's namespaced / exposed.
|
||||
Examples assume global namespace and availability from window object.
|
||||
For now API implemented as standard standard Require JS AMDs. Could attach
|
||||
to window from bundle.js. Perhaps attaching to window not best approach though...
|
||||
* Have not included validation (eg. start time < end time) or any other
|
||||
business logic such as what happens when outer interval gets dragged
|
||||
within range of inner interval. Focus is on teasing out the public API
|
||||
right now.
|
||||
* Time systems are vague right now also, I don't know how they're going
|
||||
to work or whether any API has yet been specified.
|
||||
* Not clear on the differences between real-time and follow-time as it
|
||||
concerns the time conductor? For now the API has an end bounds mode
|
||||
of FOLLOW which automatically tracks current time, and a start time mode
|
||||
of RELATIVE. I can envision a real-time plot that is not in follow time mode,
|
||||
but not sure what implication is for time conductor itself and how it
|
||||
differs from an historical plot?
|
||||
* Should the time conductor be responsible for choosing time system / domain? Currently
|
||||
it is.
|
||||
|
||||
## Use Cases
|
||||
1. Historical session is loaded and system sets time bounds on conductor
|
||||
2. Real-time session is loaded, setting custom start and end deltas
|
||||
3. User changes time of interest
|
||||
4. Plot controller listens for change to TOI
|
||||
5. Plot Controller updated on tick
|
||||
6. Plot Controller updated when user changes bounds (eg to reset plot zoom)
|
||||
7. Conductor controller needs to update bounds and mode on TC when user changes bounds
|
||||
|
||||
### Additional possible use-cases
|
||||
1. Telemetry adapter wants to indicate presence of data at a particular time
|
||||
2. Time conductor controller wants to paint map of data availability.
|
||||
|
||||
These use-cases could be features of the TimeConductor, but perhaps makes
|
||||
sense to make knowledge of data availability the sole preserve of telemetry
|
||||
adapters, not TimeConductor itself. Adapters will be ultimately responsible
|
||||
for providing these data so doesn't make much sense to duplicate elsewhere.
|
||||
The TimeConductorController - which knows tick interval on scale (which
|
||||
TimeConductor API does not) - could simply request data availability from
|
||||
telemetry API and paint it into the Time Conductor UI
|
||||
|
||||
## Example implementations of use cases
|
||||
### 1. Real time session is loaded (outside of TC) and system sets time bounds on conductor
|
||||
``` javascript
|
||||
function loadSession(telemetryMetadata) {
|
||||
var tc = MCT.conductor;
|
||||
tc.timeSystem(session.timeSystem());
|
||||
|
||||
//Set start and end modes to fixed date
|
||||
tc.mode(new FixedMode());
|
||||
|
||||
//Set both inner and outer bounds
|
||||
tc.bounds({start: session.start(), end: session.end()});
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Real-time session is loaded (outside of TC), setting custom start and end deltas
|
||||
``` javascript
|
||||
function loadSession(session) {
|
||||
var tc = MCT.conductor;
|
||||
var FIFTEEN_MINUTES = 15 * 60 * 1000;
|
||||
|
||||
// Could have a central ticking source somewhere, or connect to a
|
||||
// remote ticking source. Should not need to be done manually with
|
||||
// each session load. Actually not quite sure what to do with tick
|
||||
// sources yet.
|
||||
|
||||
var tickSource = new LocalClock();
|
||||
tickSource.attach(); // Start ticking
|
||||
|
||||
var mode = new RealtimeMode({
|
||||
startDelta: FIFTEEN_MINUTES,
|
||||
endDelta: 0 // End delta offset is from "Now" in the time system
|
||||
});
|
||||
|
||||
tc.timeSystem(session.timeSystem());
|
||||
|
||||
// Set mode to realtime, specifying a tick source
|
||||
tc.mode(mode);
|
||||
|
||||
//No need to set bounds manually, will be established by mode and the deltas specified
|
||||
}
|
||||
```
|
||||
|
||||
### 3. User changes time of interest
|
||||
```javascript
|
||||
//Somewhere in the TimeConductorController...
|
||||
function changeTOI(newTime) {
|
||||
MCT.conductor.timeOfInterest(newTime);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Plot controller listens for change to TOI
|
||||
```javascript
|
||||
// toi is attribute of Time Conductor object. Add a listener to the time
|
||||
// conductor to be alerted to changes in value
|
||||
|
||||
// Time conductor is an event emitter, listen to timeOfInterest event
|
||||
MCT.conductor.on("timeOfInterest", function (timeOfInterest) {
|
||||
plot.setTimeOfInterest(timeOfInterest);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Plot Controller updated on tick
|
||||
``` javascript
|
||||
MCT.conductor.on("bounds", function (bounds) {
|
||||
plotUpdater.setDomainBounds(bounds.start, bounds.end);
|
||||
});
|
||||
```
|
||||
|
||||
### 6. Plot Controller updated when user changes bounds (eg to reset plot zoom)
|
||||
``` javascript
|
||||
MCT.conductor.on("refresh", function (conductor) {
|
||||
plot.setBounds(conductor.bounds());
|
||||
//Also need to reset tick labels. if time system has changed.
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 7. Conductor controller needs to update bounds and mode on TC when user changes bounds
|
||||
```javascript
|
||||
var tc = MCT.conductor;
|
||||
|
||||
function dragStartHandle(finalPos){
|
||||
var bounds = tc.bounds();
|
||||
bounds.start = positionToTime(finalPos)
|
||||
tc.bounds(bounds);
|
||||
}
|
||||
|
||||
function dragEndHandle(finalPos){
|
||||
var bounds = tc.bounds();
|
||||
bounds.end = positionToTime(finalPos);
|
||||
tc.bounds(bounds);
|
||||
}
|
||||
|
||||
```
|
||||
148
platform/features/conductor-redux/src/TimeConductor.js
Normal file
148
platform/features/conductor-redux/src/TimeConductor.js
Normal file
@@ -0,0 +1,148 @@
|
||||
/*****************************************************************************
|
||||
* 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([
|
||||
"EventEmitter",
|
||||
"./UTCTimeSystem",
|
||||
"./modes/RelativeMode",
|
||||
"./modes/FixedMode"
|
||||
], function (EventEmitter, UTCTimeSystem, RelativeMode, FixedMode) {
|
||||
|
||||
/**
|
||||
* A class for setting and querying time conductor state.
|
||||
*
|
||||
* @event TimeConductor:refresh The time conductor has changed, and its values should be re-queried
|
||||
* @event TimeConductor:bounds The start time, end time, or both have been updated
|
||||
* @event TimeConductor:timeOfInterest The Time of Interest has moved.
|
||||
* @constructor
|
||||
*/
|
||||
function TimeConductor() {
|
||||
EventEmitter.call(this);
|
||||
|
||||
//The Time System
|
||||
this.system = new UTCTimeSystem();
|
||||
//The Time Of Interest
|
||||
this.toi = undefined;
|
||||
|
||||
this.bounds = {
|
||||
start: undefined,
|
||||
end: undefined
|
||||
};
|
||||
|
||||
//Default to fixed mode
|
||||
this.modeVal = new FixedMode();
|
||||
}
|
||||
|
||||
TimeConductor.prototype = Object.create(EventEmitter.prototype);
|
||||
|
||||
/**
|
||||
* Validate the given bounds. This can be used for pre-validation of
|
||||
* bounds, for example by views validating user inputs.
|
||||
* @param bounds The start and end time of the conductor.
|
||||
* @returns {string | true} A validation error, or true if valid
|
||||
*/
|
||||
TimeConductor.prototype.validateBounds = function (bounds) {
|
||||
if (!bounds.start ||
|
||||
!bounds.end ||
|
||||
isNaN(bounds.start) ||
|
||||
isNaN(bounds.end)
|
||||
) {
|
||||
return "Start and end must be specified as integer values";
|
||||
} else if (bounds.start > bounds.end){
|
||||
return "Specified start date exceeds end bound";
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
function throwOnError(validationResult) {
|
||||
if (validationResult !== true) {
|
||||
throw validationResult;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode of the time conductor.
|
||||
* @param {FixedMode | RealtimeMode} newMode
|
||||
* @fires TimeConductor#refresh
|
||||
* @returns {FixedMode | RealtimeMode}
|
||||
*/
|
||||
TimeConductor.prototype.mode = function (newMode) {
|
||||
if (arguments.length > 0) {
|
||||
this.modeVal = newMode;
|
||||
this.emit('refresh', this);
|
||||
newMode.initialize();
|
||||
}
|
||||
return this.modeVal;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} TimeConductorBounds
|
||||
* @property {number} start The start time displayed by the time conductor in ms since epoch. Epoch determined by current time system
|
||||
* @property {number} end The end time displayed by the time conductor in ms since epoch.
|
||||
*/
|
||||
/**
|
||||
* Set the start and end time of the time conductor. Basic validation of bounds is performed.
|
||||
*
|
||||
* @param {TimeConductorBounds} newBounds
|
||||
* @throws {string} Validation error
|
||||
* @fires TimeConductor#bounds
|
||||
* @returns {TimeConductorBounds}
|
||||
*/
|
||||
TimeConductor.prototype.bounds = function (newBounds) {
|
||||
if (arguments.length > 0) {
|
||||
throwOnError(this.validateBounds(newBounds));
|
||||
this.bounds = newBounds;
|
||||
this.emit('bounds', this.bounds);
|
||||
}
|
||||
return this.bounds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the time system of the TimeConductor. Time systems determine units, epoch, and other aspects of time representation.
|
||||
* @param newTimeSystem
|
||||
* @fires TimeConductor#refresh
|
||||
* @returns {TimeSystem} The currently applied time system
|
||||
*/
|
||||
TimeConductor.prototype.timeSystem = function (newTimeSystem) {
|
||||
if (arguments.length > 0) {
|
||||
this.system = newTimeSystem;
|
||||
this.emit('refresh', this);
|
||||
}
|
||||
return this.system;
|
||||
};
|
||||
|
||||
/**
|
||||
* The Time of Interest is the temporal focus of the current view. It can be manipulated by the user from the time
|
||||
* conductor or from other views.
|
||||
* @param newTOI
|
||||
* @returns {*}
|
||||
*/
|
||||
TimeConductor.prototype.timeOfInterest = function (newTOI) {
|
||||
if (arguments.length > 0) {
|
||||
this.toi = newTOI;
|
||||
this.emit('toi');
|
||||
}
|
||||
return this.toi;
|
||||
};
|
||||
|
||||
return TimeConductor;
|
||||
});
|
||||
69
platform/features/conductor-redux/src/TimeConductorBounds.js
Normal file
69
platform/features/conductor-redux/src/TimeConductorBounds.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
function TimeConductorBounds(conductor) {
|
||||
this.listeners = [];
|
||||
this.start = new TimeConductorLimit(this);
|
||||
this.end = new TimeConductorLimit(this);
|
||||
this.conductor = conductor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
TimeConductorBounds.prototype.notify = function (eventType) {
|
||||
eventType = eventType || this.conductor.EventTypes.EITHER;
|
||||
|
||||
this.listeners.forEach(function (element){
|
||||
if (element.eventType & eventType){
|
||||
element.listener(this);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Listen for changes to the bounds
|
||||
* @param listener a callback function to be called when the bounds change. The bounds object will be passed into
|
||||
* the function (ie. 'this')
|
||||
* @param eventType{TimeConductorBounds.EventType} The event type to listen to, ie. system, user, or Both. If not provied, will default to both.
|
||||
* @returns {Function} an 'unlisten' function
|
||||
*/
|
||||
TimeConductorBounds.prototype.listen = function (listener, eventType) {
|
||||
var self = this,
|
||||
wrappedListener = {
|
||||
listener: listener,
|
||||
eventType: eventType
|
||||
};
|
||||
this.listeners.push(wrappedListener);
|
||||
return function () {
|
||||
self.listeners = self.listeners.filter(function (element){
|
||||
return element !== wrappedListener;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return TimeConductorBounds;
|
||||
});
|
||||
71
platform/features/conductor-redux/src/TimeConductorLimit.js
Normal file
71
platform/features/conductor-redux/src/TimeConductorLimit.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define( [], function () {
|
||||
|
||||
/**
|
||||
* Defines a limit object for a time conductor bounds, ie. start or end values. Holds time and delta values.
|
||||
*
|
||||
* TODO: Calculation of time from delta. Should probably be done from the 'tick' function at a higher level,
|
||||
* which has start and end values in scope to do calculations.
|
||||
* @param listener
|
||||
* @constructor
|
||||
*/
|
||||
function TimeConductorLimit(listener) {
|
||||
this.deltaVal = undefined;
|
||||
this.timeVal = undefined;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set the start value for the bounds. If newVal is provided, will set the start value. May only set delta in
|
||||
* RELATIVE mode.
|
||||
* @param {Number} [newVal] a time in ms. A negative value describes a time in the past, positive in the future. A
|
||||
* start time cannot have a positive delta offset, but an end time can.
|
||||
* @param {TimeConductor.EventTypes} [eventType=TimeConductor.EventTypes.EITHER] The type of event (User, System, or
|
||||
* Either)
|
||||
* @returns {Number} the start date (in milliseconds since some epoch, depending on time system)
|
||||
*/
|
||||
TimeConductorLimit.prototype.delta = function (newVal, eventType) {
|
||||
if (arguments.length > 0) {
|
||||
this.deltaVal = newVal;
|
||||
this.listener.notify(eventType);
|
||||
}
|
||||
return this.deltaVal;
|
||||
};
|
||||
/**
|
||||
* Get or set the end value for the bounds. If newVal is provided, will set the end value. May only set time in FIXED
|
||||
* mode
|
||||
* @param {Number} [newVal] A time in ms relative to time system epoch.
|
||||
* @param {TimeConductor.EventTypes} [eventType=TimeConductor.EventTypes.EITHER] The type of event (User, System, or Either)
|
||||
* @returns {Number} the end date (in milliseconds since some epoch, depending on time system)
|
||||
*/
|
||||
TimeConductorLimit.prototype.time = function (newVal, eventType) {
|
||||
if (arguments.length > 0) {
|
||||
this.timeVal = newVal;
|
||||
this.listener.notify(eventType);
|
||||
}
|
||||
return this.timeVal;
|
||||
};
|
||||
|
||||
return TimeConductorLimit;
|
||||
});
|
||||
29
platform/features/conductor-redux/src/modes/FixedMode.js
Normal file
29
platform/features/conductor-redux/src/modes/FixedMode.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
], function () {
|
||||
function FixedMode(options) {
|
||||
|
||||
}
|
||||
return FixedMode;
|
||||
});
|
||||
71
platform/features/conductor-redux/src/modes/RealtimeMode.js
Normal file
71
platform/features/conductor-redux/src/modes/RealtimeMode.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
], function () {
|
||||
|
||||
/**
|
||||
* Class representing the real-time mode of the Time Conductor. In this mode,
|
||||
* the bounds are updated automatically based on a timing source.
|
||||
*
|
||||
* @param options
|
||||
* @constructor
|
||||
*/
|
||||
function RealtimeMode(options) {
|
||||
this.startDelta = options.startDelta;
|
||||
this.endDelta = options.endDelta;
|
||||
this.tickSource = options.tickSource;
|
||||
this.system = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.prototype.initialize = function (conductor) {
|
||||
var self = this;
|
||||
/**
|
||||
* Deltas can be specified for start and end. An end delta will mean
|
||||
* that the end bound is always in the future by 'endDelta' units
|
||||
*/
|
||||
this.startDelta = this.startDelta || conductor.timeSystem().DEFAULT_DELTA;
|
||||
this.endDelta = this.endDelta || 0;
|
||||
|
||||
function setBounds() {
|
||||
var now = conductor.timeSystem().now();
|
||||
conductor.bounds({
|
||||
start: now - self.startDelta,
|
||||
end: now + self.endDelta
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If a tick source is specified, listen for ticks
|
||||
*/
|
||||
if (this.tickSource) {
|
||||
this.tickSource.on("tick", setBounds);
|
||||
}
|
||||
//Set initial bounds
|
||||
setBounds();
|
||||
};
|
||||
|
||||
return RealtimeMode;
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user