Merge branch 'open-master' into open1223

Conflicts:
	platform/features/plot/res/templates/plot.html
This commit is contained in:
Victor Woeltjen 2015-06-19 13:34:21 -07:00
commit 3b62add011
103 changed files with 6015 additions and 1607 deletions

3
.gitignore vendored
View File

@ -17,3 +17,6 @@ target
# Closed source libraries
closed-lib
# Node dependencies
node_modules

62
app.js Normal file
View File

@ -0,0 +1,62 @@
/*global require,process,console*/
/**
* Usage:
*
* npm install minimist express
* node app.js [options]
*/
(function () {
"use strict";
var BUNDLE_FILE = 'bundles.json',
options = require('minimist')(process.argv.slice(2)),
express = require('express'),
app = express(),
fs = require('fs'),
bundles = JSON.parse(fs.readFileSync(BUNDLE_FILE, 'utf8'));
// Defaults
options.port = options.port || options.p || 8080;
['include', 'exclude', 'i', 'x'].forEach(function (opt) {
options[opt] = options[opt] || [];
// Make sure includes/excludes always end up as arrays
options[opt] = Array.isArray(options[opt]) ?
options[opt] : [options[opt]];
});
options.include = options.include.concat(options.i);
options.exclude = options.exclude.concat(options.x);
// Show command line options
if (options.help || options.h) {
console.log("\nUsage: node app.js [options]\n");
console.log("Options:");
console.log(" --help, -h Show this message.");
console.log(" --port, -p <number> Specify port.");
console.log(" --include, -i <bundle> Include the specified bundle.");
console.log(" --exclude, -x <bundle> Exclude the specified bundle.");
console.log("");
process.exit(0);
}
// Handle command line inclusions/exclusions
bundles = bundles.concat(options.include);
bundles = bundles.filter(function (bundle) {
return options.exclude.indexOf(bundle) === -1;
});
bundles = bundles.filter(function (bundle, index) { // Uniquify
return bundles.indexOf(bundle) === index;
});
// Override bundles.json for HTTP requests
app.use('/' + BUNDLE_FILE, function (req, res) {
res.send(JSON.stringify(bundles));
});
// Expose everything else as static files
app.use(express['static']('.'));
// Finally, open the HTTP server
app.listen(options.port);
}());

View File

@ -7,6 +7,7 @@
"platform/commonUI/edit",
"platform/commonUI/dialog",
"platform/commonUI/general",
"platform/commonUI/inspect",
"platform/containment",
"platform/telemetry",
"platform/features/layout",
@ -15,8 +16,8 @@
"platform/features/scrolling",
"platform/forms",
"platform/persistence/queue",
"platform/persistence/elastic",
"platform/policy",
"example/persistence",
"example/generator"
]

View File

@ -57,7 +57,8 @@
{
"key": "grid-item",
"templateUrl": "templates/items/grid-item.html",
"uses": [ "type", "action" ]
"uses": [ "type", "action" ],
"gestures": [ "info", "menu" ]
},
{
"key": "object-header",
@ -121,6 +122,12 @@
"depends": [ "typeService", "dialogService", "creationService", "policyService" ]
}
],
"runs": [
{
"implementation": "windowing/WindowTitler.js",
"depends": [ "navigationService", "$rootScope", "$document" ]
}
],
"licenses": [
{
"name": "screenfull.js",

View File

@ -21,14 +21,12 @@
-->
<span>
<div class="object-browse-bar bar abs">
<div class="items-select left abs">
<mct-representation key="'object-header'" mct-object="domainObject">
</mct-representation>
</div>
<div class="view-controls sort-controls btn-bar right abs">
<div class="btn-bar right abs">
<mct-representation key="'action-group'"
mct-object="domainObject"
parameters="{ category: 'view-control' }">
@ -39,7 +37,6 @@
ng-model="representation">
</mct-representation>
</div>
</div>
<div class='object-holder abs vscroll'>

View File

@ -20,9 +20,11 @@
at runtime from the About dialog for additional information.
-->
<div class='object-header'>
<span class='type-icon icon ui-symbol'>{{type.getGlyph()}}</span>
<span ng-if="parameters.mode" class='action'>{{parameters.mode}}</span>
<span class='type'>{{type.getName()}}</span>
<span class='title'>{{model.name}}</span>
<a id='actions-menu' class='ui-symbol invoke-menu' onclick="alert('Not yet functional. This will display a dropdown menu of options for this object.');">v</a>
<span class="label s-label">
<span class='type-icon icon ui-symbol'>{{type.getGlyph()}}</span>
<span ng-if="parameters.mode" class='action'>{{parameters.mode}}</span>
<span class='type-name'>{{type.getName()}}</span>
<span class='title-label'>{{model.name}}</span>
<!--a id='actions-menu' class='ui-symbol context-available' onclick="alert('Not yet functional. This will display a dropdown menu of options for this object.');">v</a-->
</span>
</div>

View File

@ -21,7 +21,7 @@
-->
<div class="menu-element wrapper" ng-controller="ClickAwayController as createController">
<div class="btn btn-menu create-btn major" ng-click="createController.toggle()">
<span class='ui-symbol major' href=''>+</span> Create<!--span class='ui-symbol invoke-menu'>v</span-->
<span class='ui-symbol' href=''>+</span> Create
</div>
<div class="menu dropdown super-menu" ng-show="createController.isActive()">
<mct-representation mct-object="domainObject" key="'create-menu'">

View File

@ -46,6 +46,7 @@ define(
function setNavigation(domainObject) {
$scope.navigatedObject = domainObject;
$scope.treeModel.selectedObject = domainObject;
navigationService.setNavigation(domainObject);
}
// Load the root object, put it in the scope.

View File

@ -45,8 +45,9 @@ define(
properties = type.getProperties();
function validateLocation(locatingObject) {
var locatingType = locatingObject.getCapability('type');
return policyService.allow(
var locatingType = locatingObject &&
locatingObject.getCapability('type');
return locatingType && policyService.allow(
"composition",
locatingType,
type

View File

@ -77,7 +77,19 @@ define(
return undefined;
}
return parentPersistence.persist();
return parentPersistence.persist().then(function () {
// Locate and return new Object in context of parent.
return parent
.useCapability('composition')
.then(function (children) {
var i;
for (i = 0; i < children.length; i += 1) {
if (children[i].getId() === id) {
return children[i];
}
}
});
});
});
}
@ -126,4 +138,4 @@ define(
return CreationService;
}
);
);

View File

@ -45,10 +45,12 @@ define(
// Setter for navigation; invokes callbacks
function setNavigation(value) {
navigated = value;
callbacks.forEach(function (callback) {
callback(value);
});
if (navigated !== value) {
navigated = value;
callbacks.forEach(function (callback) {
callback(value);
});
}
}
// Adds a callback

View File

@ -0,0 +1,52 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
define(
[],
function () {
"use strict";
/**
* Updates the title of the current window to reflect the name
* of the currently navigated-to domain object.
* @constructor
*/
function WindowTitler(navigationService, $rootScope, $document) {
// Look up name of the navigated domain object...
function getNavigatedObjectName() {
var navigatedObject = navigationService.getNavigation();
return navigatedObject && navigatedObject.getModel().name;
}
// Set the window title...
function setTitle(name) {
$document[0].title = name;
}
// Watch the former, and invoke the latter
$rootScope.$watch(getNavigatedObjectName, setTitle);
}
return WindowTitler;
}
);

View File

@ -34,8 +34,10 @@ define(
mockQ,
mockLog,
mockParentObject,
mockNewObject,
mockMutationCapability,
mockPersistenceCapability,
mockCompositionCapability,
mockCapabilities,
creationService;
@ -69,6 +71,10 @@ define(
"parentObject",
[ "getId", "getCapability", "useCapability" ]
);
mockNewObject = jasmine.createSpyObj(
"newObject",
[ "getId" ]
);
mockMutationCapability = jasmine.createSpyObj(
"mutation",
[ "invoke" ]
@ -77,9 +83,14 @@ define(
"persistence",
[ "persist", "getSpace" ]
);
mockCompositionCapability = jasmine.createSpyObj(
"composition",
["invoke"]
);
mockCapabilities = {
mutation: mockMutationCapability,
persistence: mockPersistenceCapability
persistence: mockPersistenceCapability,
composition: mockCompositionCapability
};
mockPersistenceService.createObject.andReturn(
@ -93,8 +104,15 @@ define(
return mockCapabilities[key].invoke(value);
});
mockPersistenceCapability.persist.andReturn(
mockPromise(true)
);
mockMutationCapability.invoke.andReturn(mockPromise(true));
mockPersistenceCapability.getSpace.andReturn("testSpace");
mockCompositionCapability.invoke.andReturn(
mockPromise([mockNewObject])
);
creationService = new CreationService(
mockPersistenceService,

View File

@ -62,6 +62,16 @@ define(
expect(callback).toHaveBeenCalledWith(testObject);
});
it("does not notify listeners when no changes occur", function () {
var testObject = { someKey: 42 },
callback = jasmine.createSpy("callback");
navigationService.addListener(callback);
navigationService.setNavigation(testObject);
navigationService.setNavigation(testObject);
expect(callback.calls.length).toEqual(1);
});
it("stops notifying listeners after removal", function () {
var testObject = { someKey: 42 },
callback = jasmine.createSpy("callback");

View File

@ -8,5 +8,6 @@
"creation/LocatorController",
"navigation/NavigateAction",
"navigation/NavigationService",
"windowing/FullscreenAction"
"windowing/FullscreenAction",
"windowing/WindowTitler"
]

View File

@ -0,0 +1,80 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
/**
* WindowTitlerSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/windowing/WindowTitler"],
function (WindowTitler) {
"use strict";
describe("The window titler", function () {
var mockNavigationService,
mockRootScope,
mockDocument,
mockDomainObject,
titler;
beforeEach(function () {
mockNavigationService = jasmine.createSpyObj(
'navigationService',
[ 'getNavigation' ]
);
mockRootScope = jasmine.createSpyObj(
'$rootScope',
[ '$watch' ]
);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getModel']
);
mockDocument = [{}];
mockDomainObject.getModel.andReturn({ name: 'Test name' });
mockNavigationService.getNavigation.andReturn(mockDomainObject);
titler = new WindowTitler(
mockNavigationService,
mockRootScope,
mockDocument
);
});
it("listens for changes to the name of the navigated object", function () {
expect(mockRootScope.$watch).toHaveBeenCalledWith(
jasmine.any(Function),
jasmine.any(Function)
);
expect(mockRootScope.$watch.mostRecentCall.args[0]())
.toEqual('Test name');
});
it("sets the title to the name of the navigated object", function () {
mockRootScope.$watch.mostRecentCall.args[1]("Some name");
expect(mockDocument[0].title).toEqual("Some name");
});
});
}
);

View File

@ -25,7 +25,7 @@
<a href=""
ng-click="ngModel.cancel()"
ng-if="ngModel.cancel"
class="btn normal outline ui-symbol close">
class="btn normal ui-symbol close">
x
</a>
<div class="abs contents" ng-transclude>

View File

@ -33,8 +33,6 @@
<mct-representation key="'edit-action-buttons'"
mct-object="domainObject"
class='conclude-editing'>
<!--a class='btn major' href=''>Save<span id='save-actions-menu' class='ui-symbol invoke-menu'>v</span></a>
<a class='btn subtle' href=''>Cancel</a-->
</mct-representation>
</div>
</div>

View File

@ -181,7 +181,7 @@
"key": "label",
"templateUrl": "templates/label.html",
"uses": [ "type" ],
"gestures": [ "drag", "menu" ]
"gestures": [ "drag", "menu", "info" ]
},
{
"key": "node",

View File

@ -61,6 +61,15 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*
@mixin invokeMenu($baseColor: $colorBodyFg) {
$c: $baseColor;
color: $c;
&:hover {
color: lighten($c, $ltGamma);
}
}
*/
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@ -186,9 +195,9 @@
color: #666666; }
/* line 116, ../sass/forms/_elems.scss */
.form .form-row .selector-list {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@ -225,9 +234,9 @@ label.form-control.checkbox input {
vertical-align: top; }
/* line 159, ../sass/forms/_elems.scss */
.l-result div.s-hint {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
background: rgba(255, 153, 0, 0.8);
display: block;
color: #ffd699;
@ -258,9 +267,9 @@ label.form-control.checkbox input {
.edit-main textarea {
-moz-appearance: none;
-webkit-appearance: none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@ -302,13 +311,12 @@ label.form-control.checkbox input {
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* line 22, ../sass/forms/_text-input.scss */
input[type="text"],
input[type="date"] {
input[type="text"] {
-moz-appearance: none;
-webkit-appearance: none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@ -322,32 +330,10 @@ input[type="date"] {
outline: none;
padding: 0 3px; }
/* line 33, ../sass/forms/_mixins.scss */
input[type="text"].error,
input[type="date"].error {
input[type="text"].error {
background: rgba(255, 0, 0, 0.5); }
/* line 61, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/css3/_user-interface.scss */
input[type="text"]:-moz-placeholder,
input[type="date"]:-moz-placeholder {
color: gray;
font-style: italic; }
/* line 64, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/css3/_user-interface.scss */
input[type="text"]::-moz-placeholder,
input[type="date"]::-moz-placeholder {
color: gray;
font-style: italic; }
/* line 67, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/css3/_user-interface.scss */
input[type="text"]:-ms-input-placeholder,
input[type="date"]:-ms-input-placeholder {
color: gray;
font-style: italic; }
/* line 56, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/css3/_user-interface.scss */
input[type="text"]::-webkit-input-placeholder,
input[type="date"]::-webkit-input-placeholder {
color: gray;
font-style: italic; }
/* line 34, ../sass/forms/_text-input.scss */
input[type="text"].numeric,
input[type="date"].numeric {
/* line 29, ../sass/forms/_text-input.scss */
input[type="text"].numeric {
text-align: right; }
/*****************************************************************************
@ -373,23 +359,23 @@ input[type="date"] {
*****************************************************************************/
/* line 22, ../sass/forms/_selects.scss */
.form-control.select {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzRkNGQ0ZCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzQwNDA0MCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzUyNTI1MiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzQ1NDU0NSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4d4d4d), color-stop(100%, #404040));
background-image: -moz-linear-gradient(#4d4d4d, #404040);
background-image: -webkit-linear-gradient(#4d4d4d, #404040);
background-image: linear-gradient(#4d4d4d, #404040);
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #525252), color-stop(100%, #454545));
background-image: -moz-linear-gradient(#525252, #454545);
background-image: -webkit-linear-gradient(#525252, #454545);
background-image: linear-gradient(#525252, #454545);
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
border: none;
border-top: 1px solid #666666;
border-top: 1px solid #575757;
color: #999;
display: inline-block;
cursor: pointer;
@ -397,14 +383,21 @@ input[type="date"] {
margin: 0 0 2px 2px;
overflow: hidden;
position: relative; }
/* line 148, ../sass/_mixins.scss */
/* line 152, ../sass/_mixins.scss */
.form-control.select:not(.disabled):hover {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzY2NjY2NiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzRkNGQ0ZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #666666), color-stop(100%, #4d4d4d));
background-image: -moz-linear-gradient(#666666, #4d4d4d);
background-image: -webkit-linear-gradient(#666666, #4d4d4d);
background-image: linear-gradient(#666666, #4d4d4d); }
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #636363), color-stop(100%, #575757));
background-image: -moz-linear-gradient(#636363, #575757);
background-image: -webkit-linear-gradient(#636363, #575757);
background-image: linear-gradient(#636363, #575757);
color: #bdbdbd; }
/* line 155, ../sass/_mixins.scss */
.form-control.select:not(.disabled):hover.btn-menu .invoke-menu {
color: #878787; }
/* line 160, ../sass/_mixins.scss */
.form-control.select.btn-menu .invoke-menu {
color: #757575; }
/* line 29, ../sass/forms/_selects.scss */
.form-control.select select {
-moz-appearance: none;
@ -461,9 +454,9 @@ input[type="date"] {
.channel-selector .treeview {
-moz-appearance: none;
-webkit-appearance: none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;

View File

@ -61,6 +61,15 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*
@mixin invokeMenu($baseColor: $colorBodyFg) {
$c: $baseColor;
color: $c;
&:hover {
color: lighten($c, $ltGamma);
}
}
*/
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@ -92,23 +101,23 @@
top: 0; }
/* line 29, ../sass/items/_item.scss */
.items-holder .item.grid-item {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzU5NTk1OSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzRkNGQ0ZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzVlNWU1ZSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzUyNTI1MiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #595959), color-stop(100%, #4d4d4d));
background-image: -moz-linear-gradient(#595959, #4d4d4d);
background-image: -webkit-linear-gradient(#595959, #4d4d4d);
background-image: linear-gradient(#595959, #4d4d4d);
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #5e5e5e), color-stop(100%, #525252));
background-image: -moz-linear-gradient(#5e5e5e, #525252);
background-image: -webkit-linear-gradient(#5e5e5e, #525252);
background-image: linear-gradient(#5e5e5e, #525252);
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
border: none;
border-top: 1px solid #737373;
border-top: 1px solid #636363;
color: #999;
display: inline-block;
box-sizing: border-box;
@ -119,14 +128,21 @@
margin-bottom: 3px;
margin-right: 3px;
position: relative; }
/* line 148, ../sass/_mixins.scss */
/* line 152, ../sass/_mixins.scss */
.items-holder .item.grid-item:not(.disabled):hover {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzczNzM3MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU5NTk1OSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzcwNzA3MCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #737373), color-stop(100%, #595959));
background-image: -moz-linear-gradient(#737373, #595959);
background-image: -webkit-linear-gradient(#737373, #595959);
background-image: linear-gradient(#737373, #595959); }
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #707070), color-stop(100%, #636363));
background-image: -moz-linear-gradient(#707070, #636363);
background-image: -webkit-linear-gradient(#707070, #636363);
background-image: linear-gradient(#707070, #636363);
color: #bdbdbd; }
/* line 155, ../sass/_mixins.scss */
.items-holder .item.grid-item:not(.disabled):hover.btn-menu .invoke-menu {
color: #949494; }
/* line 160, ../sass/_mixins.scss */
.items-holder .item.grid-item.btn-menu .invoke-menu {
color: #828282; }
/* line 42, ../sass/items/_item.scss */
.items-holder .item.grid-item:hover .item-main .item-type {
color: #0099cc !important; }
@ -184,40 +200,41 @@
font-size: 0.8em; }
/* line 104, ../sass/items/_item.scss */
.items-holder .item.grid-item.selected {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwYmZmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwYWNlNiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzBhYzJmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwYjRmMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #00bfff), color-stop(100%, #00ace6));
background-image: -moz-linear-gradient(#00bfff, #00ace6);
background-image: -webkit-linear-gradient(#00bfff, #00ace6);
background-image: linear-gradient(#00bfff, #00ace6);
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #0ac2ff), color-stop(100%, #00b4f0));
background-image: -moz-linear-gradient(#0ac2ff, #00b4f0);
background-image: -webkit-linear-gradient(#0ac2ff, #00b4f0);
background-image: linear-gradient(#0ac2ff, #00b4f0);
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px;
border: none;
border-top: 1px solid #33ccff;
border-top: 1px solid #14c4ff;
color: #999;
display: inline-block;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzMzY2NmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwOTljYyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #33ccff), color-stop(100%, #0099cc));
background-image: -moz-linear-gradient(#33ccff, #0099cc);
background-image: -webkit-linear-gradient(#33ccff, #0099cc);
background-image: linear-gradient(#33ccff, #0099cc);
color: #80dfff; }
/* line 156, ../sass/_mixins.scss */
/* line 152, ../sass/_mixins.scss */
.items-holder .item.grid-item.selected:not(.disabled):hover {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzY2ZDlmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwYmZmZiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzJlY2JmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzE0YzRmZiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #66d9ff), color-stop(100%, #00bfff));
background-image: -moz-linear-gradient(#66d9ff, #00bfff);
background-image: -webkit-linear-gradient(#66d9ff, #00bfff);
background-image: linear-gradient(#66d9ff, #00bfff); }
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #2ecbff), color-stop(100%, #14c4ff));
background-image: -moz-linear-gradient(#2ecbff, #14c4ff);
background-image: -webkit-linear-gradient(#2ecbff, #14c4ff);
background-image: linear-gradient(#2ecbff, #14c4ff);
color: #bdbdbd; }
/* line 155, ../sass/_mixins.scss */
.items-holder .item.grid-item.selected:not(.disabled):hover.btn-menu .invoke-menu {
color: #75ddff; }
/* line 160, ../sass/_mixins.scss */
.items-holder .item.grid-item.selected.btn-menu .invoke-menu {
color: #52d4ff; }
/* line 109, ../sass/items/_item.scss */
.items-holder .item.grid-item.selected .item-type, .items-holder .item.grid-item.selected .top-bar .icon:not(.alert) {
color: #80dfff; }

View File

@ -1,350 +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.
*****************************************************************************/
/*****************************************************************************
* 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.
*****************************************************************************/
/*****************************************************************************
* 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.
*****************************************************************************/
/*****************************************************************************
* 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.
*****************************************************************************/
/* line 31, ../sass/plots/_plots-main.scss */
.gl-plot {
color: #999;
font-size: 0.7rem;
position: relative;
width: 100%;
height: 100%;
/****************************** Limits and Out-of-Bounds data */ }
/* line 38, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area {
position: absolute; }
/* line 41, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area.gl-plot-x {
top: auto;
right: 0;
bottom: 5px;
left: 60px;
height: 32px;
width: auto;
overflow: hidden; }
/* line 50, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area.gl-plot-y {
top: 29px;
right: auto;
bottom: 37px;
left: 0;
width: 60px; }
/* line 59, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-coords {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background: black;
color: #e6e6e6;
padding: 2px 5px;
position: absolute;
top: 39px;
right: auto;
bottom: auto;
left: 70px;
z-index: 10; }
/* line 71, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-coords:empty {
display: none; }
/* line 76, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-display-area {
position: absolute;
top: 29px;
right: 0;
bottom: 37px;
left: 60px;
cursor: crosshair;
border: 1px solid #4d4d4d; }
/* line 86, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label,
.gl-plot .l-plot-label {
color: #cccccc;
position: absolute;
text-align: center; }
/* line 94, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label.gl-plot-x-label, .gl-plot .gl-plot-label.l-plot-x-label,
.gl-plot .l-plot-label.gl-plot-x-label,
.gl-plot .l-plot-label.l-plot-x-label {
top: auto;
right: 0;
bottom: 0;
left: 0;
height: auto; }
/* line 103, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label.gl-plot-y-label, .gl-plot .gl-plot-label.l-plot-y-label,
.gl-plot .l-plot-label.gl-plot-y-label,
.gl-plot .l-plot-label.l-plot-y-label {
-moz-transform-origin: 50% 0;
-ms-transform-origin: 50% 0;
-webkit-transform-origin: 50% 0;
transform-origin: 50% 0;
-moz-transform: translateX(-50%) rotate(-90deg);
-ms-transform: translateX(-50%) rotate(-90deg);
-webkit-transform: translateX(-50%) rotate(-90deg);
transform: translateX(-50%) rotate(-90deg);
display: inline-block;
margin-left: 5px;
left: 0;
top: 50%;
white-space: nowrap; }
/* line 117, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-y-options {
position: absolute;
top: 50%;
right: auto;
bottom: auto;
left: auto5px;
margin-top: -16px;
height: auto;
min-height: 32px;
width: 32px; }
/* line 131, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash {
position: absolute;
border: 0 rgba(255, 255, 255, 0.3) dashed; }
/* line 134, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash.hash-v {
border-right-width: 1px;
height: 100%; }
/* line 138, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash.hash-h {
border-bottom-width: 1px;
width: 100%; }
/* line 144, ../sass/plots/_plots-main.scss */
.gl-plot .gl-plot-legend {
position: absolute;
top: 0;
right: 0;
bottom: auto;
left: 0;
height: 24px;
overflow-x: hidden;
overflow-y: auto; }
/* line 157, ../sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar,
.gl-plot .l-oob-data {
position: absolute;
left: 0;
right: 0;
width: auto; }
/* line 165, ../sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar {
height: auto;
z-index: 0; }
/* line 173, ../sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar.s-limit-yellow {
background: rgba(157, 117, 0, 0.2); }
/* line 174, ../sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar.s-limit-red {
background: rgba(170, 0, 0, 0.2); }
/* line 177, ../sass/plots/_plots-main.scss */
.gl-plot .l-oob-data {
overflow: hidden;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
width: auto;
height: auto;
pointer-events: none;
height: 10px;
z-index: 1; }
/* line 185, ../sass/plots/_plots-main.scss */
.gl-plot .l-oob-data.l-oob-data-up {
top: 0;
bottom: auto;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjEuMCIgeDI9IjAuNSIgeTI9IjAuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzc3NDhkNiIgc3RvcC1vcGFjaXR5PSIwLjAiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiM3NzQ4ZDYiIHN0b3Atb3BhY2l0eT0iMC41Ii8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g');
background-size: 100%;
background-image: -moz-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: -webkit-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: linear-gradient(0deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
/* line 190, ../sass/plots/_plots-main.scss */
.gl-plot .l-oob-data.l-oob-data-dwn {
bottom: 0;
top: auto;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzc3NDhkNiIgc3RvcC1vcGFjaXR5PSIwLjAiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiM3NzQ4ZDYiIHN0b3Atb3BhY2l0eT0iMC41Ii8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g');
background-size: 100%;
background-image: -moz-linear-gradient(270deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: -webkit-linear-gradient(270deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: linear-gradient(180deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
/* line 200, ../sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item,
.gl-plot-legend .legend-item,
.legend .plot-legend-item,
.legend .legend-item {
display: inline-block;
margin-right: 10px; }
/* line 204, ../sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item span,
.gl-plot-legend .legend-item span,
.legend .plot-legend-item span,
.legend .legend-item span {
vertical-align: middle; }
/* line 207, ../sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item .plot-color-swatch,
.gl-plot-legend .plot-legend-item .color-swatch,
.gl-plot-legend .legend-item .plot-color-swatch,
.gl-plot-legend .legend-item .color-swatch,
.legend .plot-legend-item .plot-color-swatch,
.legend .plot-legend-item .color-swatch,
.legend .legend-item .plot-color-swatch,
.legend .legend-item .color-swatch {
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
display: inline-block;
height: 8px;
width: 8px; }
/* line 220, ../sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item {
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
color: #fff;
line-height: 1.5em;
padding: 0px 5px; }
/* line 226, ../sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item .plot-color-swatch {
border: 1px solid #333;
height: 9px;
width: 9px; }
/* line 234, ../sass/plots/_plots-main.scss */
.tick {
position: absolute;
border: 0 rgba(255, 255, 255, 0.3) solid; }
/* line 237, ../sass/plots/_plots-main.scss */
.tick.tick-x {
border-right-width: 1px;
height: 100%; }
/* line 243, ../sass/plots/_plots-main.scss */
.gl-plot-tick,
.tick-label {
font-size: 0.7rem;
position: absolute;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; }
/* line 251, ../sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-x-tick-label, .gl-plot-tick.tick-label-x,
.tick-label.gl-plot-x-tick-label,
.tick-label.tick-label-x {
right: auto;
bottom: auto;
left: auto;
height: auto;
width: 20%;
margin-left: -10%;
text-align: center; }
/* line 261, ../sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-y-tick-label, .gl-plot-tick.tick-label-y,
.tick-label.gl-plot-y-tick-label,
.tick-label.tick-label-y {
top: auto;
height: 1em;
width: auto;
margin-bottom: -0.5em;
text-align: right; }
/* line 273, ../sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-x-tick-label {
top: 5px; }
/* line 276, ../sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-y-tick-label {
right: 5px;
left: 5px; }
/* line 283, ../sass/plots/_plots-main.scss */
.tick-label.tick-label-x {
top: 0; }
/* line 286, ../sass/plots/_plots-main.scss */
.tick-label.tick-label-y {
right: 0;
left: 0; }

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,15 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*
@mixin invokeMenu($baseColor: $colorBodyFg) {
$c: $baseColor;
color: $c;
&:hover {
color: lighten($c, $ltGamma);
}
}
*/
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@ -86,7 +95,7 @@
ul.tree {
margin: 0;
padding: 0; }
/* line 208, ../sass/_mixins.scss */
/* line 264, ../sass/_mixins.scss */
ul.tree li {
list-style-type: none;
margin: 0;
@ -97,17 +106,17 @@ ul.tree {
position: relative; }
/* line 27, ../sass/tree/_tree.scss */
ul.tree li span.tree-item {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-transition: background-color 0.25s;
-o-transition: background-color 0.25s;
-webkit-transition: background-color 0.25s;
transition: background-color 0.25s;
display: block;
font-size: 0.80rem;
height: 1.5rem;
line-height: 1.5rem;
height: 1.4rem;
line-height: 1.4rem;
margin-bottom: 3px;
position: relative; }
/* line 38, ../sass/tree/_tree.scss */
@ -168,7 +177,7 @@ ul.tree {
width: auto;
height: auto;
display: block;
left: 25px;
left: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; }
@ -207,17 +216,16 @@ ul.tree {
/* line 125, ../sass/tree/_tree.scss */
ul.tree li span.tree-item:not(.loading) {
cursor: pointer; }
/* line 130, ../sass/tree/_tree.scss */
/* line 129, ../sass/tree/_tree.scss */
ul.tree li span.tree-item .context-trigger {
display: none;
top: -1px;
position: absolute;
right: 3px; }
/* line 136, ../sass/tree/_tree.scss */
ul.tree li span.tree-item .context-trigger .btn-invoke-menu {
/* line 135, ../sass/tree/_tree.scss */
ul.tree li span.tree-item .context-trigger .invoke-menu {
font-size: 0.75em;
height: 0.9rem;
line-height: 0.9rem; }
/* line 145, ../sass/tree/_tree.scss */
/* line 144, ../sass/tree/_tree.scss */
ul.tree ul.tree {
margin-left: 15px; }

View File

@ -2,7 +2,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg>
<metadata>
Created by FontForge 20090622 at Mon May 4 20:21:42 2015
Created by FontForge 20090622 at Tue Jun 9 23:00:40 2015
By deploy user
Copyright 2015 Adobe Systems Incorporated. All rights reserved.
</metadata>
@ -62,8 +62,10 @@ q52 -180 95 -231q42 53 88 212z" />
d="M193 787v-193h-193v193h193zM193 491v-195h-193v195h193zM193 193v-193h-193v193h193zM671 732v-82h-388v82h388zM671 435v-81h-388v81h388zM671 138v-82h-388v82h388z" />
<glyph glyph-name="eight" unicode="8" horiz-adv-x="636"
d="M625 735v-318h-625v318h625zM625 315v-315h-625v315h625z" />
<glyph glyph-name="nine" unicode="9" horiz-adv-x="636"
d="M267 735v-319h-267v319h267zM267 315v-315h-267v315h267zM630 735v-319h-267v319h267zM630 315v-315h-267v315h267z" />
<glyph glyph-name="nine" unicode="9"
d="M328 469q0 -20 -13.5 -33.5t-33.5 -13.5h-234q-20 0 -33.5 13.5t-13.5 33.5v234q0 19 14 33t33 14h234q20 0 33.5 -13.5t13.5 -33.5v-234zM750 469q0 -20 -13.5 -33.5t-33.5 -13.5h-234q-20 0 -33.5 13.5t-13.5 33.5v234q0 20 13.5 33.5t33.5 13.5h234q19 0 33 -14
t14 -33v-234zM328 47q0 -20 -13.5 -33.5t-33.5 -13.5h-234q-19 0 -33 14t-14 33v234q0 20 13.5 33.5t33.5 13.5h234q20 0 33.5 -13.5t13.5 -33.5v-234zM750 47q0 -19 -14 -33t-33 -14h-234q-20 0 -33.5 13.5t-13.5 33.5v234q0 20 13.5 33.5t33.5 13.5h234q20 0 33.5 -13.5
t13.5 -33.5v-234z" />
<glyph glyph-name="colon" unicode=":" horiz-adv-x="625"
d="M625 -19l-397 397l397 397v-794zM173 756v-735h-173v735h173z" />
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="624"
@ -163,8 +165,8 @@ d="M123 367l-123 123v147l123 -123l220 221v-147zM123 0l-123 123v147l123 -123l220
d="M123 93l-123 123v147l123 -123l220 220v-147zM485 262v71h313v-71h-313z" />
<glyph glyph-name="l" unicode="l" horiz-adv-x="617"
d="M551 386h66v-386h-617v386h63v106q0 100 72 171.5t173 71.5q99 0 171 -71.5t72 -171.5v-106zM173 492v-106h267v106q0 56 -38.5 94.5t-93.5 38.5q-56 0 -95.5 -39t-39.5 -94z" />
<glyph glyph-name="m" unicode="m" horiz-adv-x="804"
d="M804 729v-156h-804v156h804zM804 445v-160h-804v160h804zM804 158v-158h-804v158h804z" />
<glyph glyph-name="m" unicode="m" horiz-adv-x="751"
d="M751 563h-751v188h751v-188zM751 282h-751v187h751v-187zM751 0h-751v188h751v-188z" />
<glyph glyph-name="n" unicode="n" horiz-adv-x="738"
d="M690 697q48 -50 48 -88q0 -18 -10 -26l-243 -243l-3 -3l-4 -2l-227 -78l77 228l2 4l3 3l242 243q22 19 57 3q29 -14 58 -41zM461 371l1 2l-3 50l-34 2h-9v10v28l-51 6l-2 -1l-32 -97l33 -33zM249 512l-134 -389l304 104v-215q-136 -8 -246.5 29t-172.5 93v561
q48 -42 125 -75.5t172 -43.5l-24 -25l-17 -17z" />
@ -232,6 +234,22 @@ d="M748 750l-375 -750l-374 750h749z" />
d="M-1 0l375 750l374 -750h-749z" />
<glyph glyph-name="icircumflex" unicode="&#xee;" horiz-adv-x="748"
d="M748 750l-375 -375l-374 375h749zM748 375l-375 -374l-374 374h749z" />
<glyph glyph-name="idieresis" unicode="&#xef;"
d="M0 749l750 -375l-750 -374v749z" />
<glyph glyph-name="ntilde" unicode="&#xf1;"
d="M283 751v-751h-188v751h188zM658 751v-751h-188v751h188z" />
<glyph glyph-name="ograve" unicode="&#xf2;" horiz-adv-x="751"
d="M469 563h-102q-74 0 -126.5 -52.5t-52.5 -126.5v-102h-94q-38 0 -66 27.5t-28 65.5v282q0 38 28 66t66 28h281q39 0 66.5 -28t27.5 -66v-94zM657 469q38 0 66 -27.5t28 -66.5v-281q0 -38 -28 -66t-66 -28h-282q-38 0 -65.5 28t-27.5 66v281q0 39 27.5 66.5t65.5 27.5h282
z" />
<glyph glyph-name="oacute" unicode="&#xf3;" horiz-adv-x="751"
d="M216 375l187 -187h-309q-38 0 -66 27.5t-28 66.5v375q0 38 28 66t66 28h375q39 0 66.5 -28t27.5 -66v-309l-188 187zM751 422v-422h-422v94h234l-281 281l93 94l282 -281v234h94z" />
<glyph glyph-name="ocircumflex" unicode="&#xf4;" horiz-adv-x="751"
d="M610 751q58 0 99.5 -41.5t41.5 -99.5v-469q0 -59 -41.5 -100t-99.5 -41h-469q-59 0 -100 41t-41 100v469q0 58 41 99.5t100 41.5h469zM610 282v328h-328l93 -94l-234 -375l375 234z" />
<glyph glyph-name="otilde" unicode="&#xf5;" horiz-adv-x="657"
d="M329 657q136 0 232 -96t96 -232t-96 -232.5t-232 -96.5q-137 0 -233 96t-96 233q0 136 96.5 232t232.5 96zM329 329v246q-101 0 -175 -72zM422 704q0 -20 -13.5 -33.5t-33.5 -13.5h-46h-47q-20 0 -33.5 13.5t-13.5 33.5t13.5 33.5t33.5 13.5h93q20 0 33.5 -13.5
t13.5 -33.5z" />
<glyph glyph-name="odieresis" unicode="&#xf6;"
d="M328 562v-375h-328v375h328zM750 562v-375h-328v375h328z" />
<glyph glyph-name="fraction" unicode="&#x2044;" horiz-adv-x="761"
d="M380 751q158 0 269.5 -111.5t111.5 -268.5q0 -133 -82.5 -236.5t-209.5 -134.5l-4 491l-176 -490q-126 31 -207.5 134.5t-81.5 235.5q0 157 111.5 268.5t268.5 111.5zM168 488l55 20l-34 94l-56 -20zM410 530v100h-59v-100h59zM593 488l34 94l-55 20l-34 -94z" />
<glyph glyph-name="H.002" horiz-adv-x="803"

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -19,13 +19,17 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
// Features
$enableImageryThumbs: false; // Set to true if historical imagery thumbnails are supported
// Margins, spacing, radii
$bodyMargin: 10px;
$interiorMargin: 5px;
$interiorMarginLg: $interiorMargin * 2;
$interiorMarginSm: 3px;
$basicCr: 3px;
$controlCr: $basicCr;
$basicCr: 2px;
$controlCr: 2px;
$smallCr: 2px;
$badgeW: 35px;
@ -34,9 +38,12 @@ $colorBodyBg: #333;
$colorBodyFg: #999;
$colorFooterBg: #000;
$colorKey: #0099cc;
$colorKeySelectedBg: #005177;
$colorKeyFg: #fff;
$colorAlt1: #ffc700;
$colorAlert: #ff3c00;
$colorPausedBg: #c56f01;
$colorPausedFg: #fff;
$colorCheck: $colorKey;
$colorCreateBtn: $colorKey;
$colorInteriorBorder: lighten($colorBodyBg, 10%);
@ -50,7 +57,18 @@ $colorLimitYellow: #9d7500;
$colorLimitRed: #aa0000;
$colorTelemFresh: #fff;
$colorTelemStale: #888;
$styleTelemStale: italic;
$colorInfoBubbleFg: #666;
$colorInfoBubbleBg: #ddd;
$colorThumbsBubbleFg: lighten($colorBodyFg, 10%);
$colorThumbsBubbleBg: lighten($colorBodyBg, 10%);
$colorLimitYellow: #9d7500;
$colorLimitRed: #aa0000;
$colorTelemFresh: #fff;
$colorTelemStale: #888;
$styleTelemState: italic;
$colorInfoBubbleFg: #666;
$colorInfoBubbleBg: #ddd;
// Ratios
$ltGamma: 20%;
@ -108,7 +126,7 @@ $controlDisabledOpacity: 0.3;
$formLabelW: 20%;
$formInputH: 22px;
$formRowCtrlsH: 14px;
$menuLineH: 1.5rem;
$menuLineH: 1.4rem;
$scrollbarTrackSize: 10px;
$scrollbarTrackColorBg: rgba(#000, 0.4);
$btnStdH: 25px;
@ -124,3 +142,19 @@ $tickLblH: 15px;
$tickLblW: 50px;
$tickH: $ticksH - $tickLblVMargin - $tickLblH;
$tickW: 1px;
// Imagery
$imageMainControlBarH: 20px;
$imageThumbsD: 120px;
$imageThumbsWrapperH: $imageThumbsD * 1.4;
$imageThumbPad: 1px;
// Bubbles
$bubbleArwSize: 10px;
$bubblePad: $interiorMargin;
$bubbleMinW: 100px;
$bubbleMaxW: 300px;
// Timing
$controlFadeMs: 100ms;

View File

@ -44,7 +44,7 @@ a.disabled {
}
@include keyframes(pulse) {
0% { opacity: 0.2; }
0% { opacity: 0.5; }
100% { opacity: 1; }
}
@ -57,5 +57,5 @@ a.disabled {
}
.pulse {
@include pulse(1000ms);
@include pulse(750ms);
}

View File

@ -69,6 +69,10 @@ span {
*/
}
mct-container {
display: block;
}
.abs {
position: absolute;
top: 0;
@ -117,6 +121,13 @@ span {
display: none !important;
}
.paused {
&:not(.s-btn) {
border-color: $colorPausedBg !important;
color: $colorPausedBg !important;
}
}
.sep {
color: rgba(#fff, 0.2);
}

View File

@ -36,7 +36,7 @@
// Don't pad in from top and bottom
//top: 0; bottom: 0;
.object-browse-bar {
.t-btn.key-window {
.btn.key-window {
// Hide the Open in New Window button
display: none;
}

View File

@ -42,12 +42,6 @@
&.major {
font-size: 1.65em;
}
&:hover {
// color: lighten($c, $ltGamma);
.invoke-menu {
// color: lighten($colorBodyBg, $ltGamma * 2);
}
}
}
}
@ -56,36 +50,35 @@
}
.invoke-menu {
@include invokeMenu($colorKey);
//@include invokeMenu(); // $colorKey
text-shadow: none;
display: inline-block;
font-size: 1rem;
font-size: 0.8rem;
vertical-align: middle;
}
.btn-menu .invoke-menu,
.icon.major .invoke-menu {
margin-left: $interiorMargin;
}
.icon-buttons-main .invoke-menu {
@include invokeMenu(lighten($colorBodyBg, $ltGamma));
}
.menu-element .invoke-menu {
margin-left: $interiorMarginSm;
}
/*
.object-header .type-icon {
color: $colorKey;
margin-right: $interiorMargin;
margin-right: $interiorMarginSm;
}
*/
.menu .type-icon,
.tree-item .type-icon,
.icon-btn .menu.dropdown .icon,
.super-menu.menu.dropdown .icon {
font-size: $menuLineH * 0.93;
.super-menu.menu .type-icon {
font-size: $menuLineH * 0.8; //.93
line-height: $menuLineH * 1.13;
position: absolute;
}
.super-menu.menu.dropdown .icon {
font-size: $menuLineH * 0.95
}

View File

@ -46,6 +46,9 @@
@import "controls/lists";
@import "controls/menus";
@import "controls/time-controller";
@import "edit/editor";
@import "features/imagery";
@import "features/time-display";
@import "forms/mixins";
@import "forms/elems";
@import "forms/validation";

View File

@ -26,6 +26,16 @@
width: auto; height: auto;
}
@mixin trans-prop-nice($props, $t) {
@if $t == 0 {
@include transition-property(none);
} @else {
@include transition-property($props);
@include transition-duration($t);
@include transition-timing-function(ease-in-out);
}
}
@mixin trans-prop-nice-fade($t: 0.5s) {
@if $t == 0 {
@include transition-property(none);
@ -42,6 +52,12 @@
@include transition-timing-function(ease-in-out);
}
@mixin trans-prop-nice-resize-w($t: 0.5s) {
@include transition-property(width, left, right);
@include transition-duration($t);
@include transition-timing-function(ease-in-out);
}
@mixin triangle-right($size, $color) {
$size: $size/2;
$ratio: 1;
@ -62,6 +78,31 @@
border-right: $size/$ratio solid transparent;
}
@mixin triangle($dir: "left", $size: 5px, $ratio: 1, $color: red) {
//$size: $size*2;
width: 0;
height: 0;
$slopedB: $size/$ratio solid transparent;
$straightB: $size solid $color;
@if $dir == "up" {
border-left: $slopedB;
border-right: $slopedB;
border-bottom: $straightB;
} @else if $dir == "right" {
border-top: $slopedB;
border-bottom: $slopedB;
border-left: $straightB;
} @else if $dir == "down" {
border-left: $slopedB;
border-right: $slopedB;
border-top: $straightB;
} @else {
border-top: $slopedB;
border-bottom: $slopedB;
border-right: $straightB;
}
}
@mixin bgDiagonalStripes($c: yellow, $a: 0.1, $d: 40px) {
@include background-image(linear-gradient(-45deg,
rgba($c, $a) 25%, transparent 25%,
@ -90,20 +131,35 @@
}
@mixin containerSubtle($bg: $colorBodyBg, $fg: $colorBodyFg, $hover: false) {
@include background-image(linear-gradient(lighten($bg, 10%), lighten($bg, 5%)));
$ltnRatio: 7%;
$gradRatio: 5%;
$hovRatio: 7%;
$bgBase: lighten($bg, $ltnRatio);
$fgBase: lighten($fg, $ltnRatio);
$gradC1: lighten($bgBase, $gradRatio);
$gradC2: $bgBase;
$cInvokeBase: lighten($gradC1, $ltnRatio*2);
@include background-image(linear-gradient($gradC1, $gradC2));
@include border-radius($controlCr);
@include box-sizing(border-box);
// @include box-shadow(rgba(black, 0.3) 0 1px 2px);
@include boxShdwSubtle();
border: none;
border-top: 1px solid lighten($bg, 20%);
border-top: 1px solid lighten($gradC1, 2%);
color: $fg;
display: inline-block;
@if $hover == true {
&:hover {
@include background-image(linear-gradient(lighten($bg, 20%), lighten($bg, 15%)));
&:not(.disabled):hover {
@include background-image(linear-gradient(lighten($gradC1, $hovRatio), lighten($gradC2, $hovRatio)));
color: lighten($fgBase, $hovRatio);
&.btn-menu .invoke-menu {
color: lighten($cInvokeBase, $hovRatio);
}
}
}
&.btn-menu .invoke-menu {
color: $cInvokeBase;
}
}
@mixin sliderTrack($bg: $scrollbarTrackColorBg) {
@ -144,18 +200,16 @@
}
@mixin btnSubtle($bg: $colorBodyBg, $fg: $colorBodyFg) {
@include containerSubtle($bg, $fg);
&:not(.disabled):hover {
@include background-image(linear-gradient(lighten($bg, 20%), lighten($bg, 10%)));
}
@include containerSubtle($bg, $fg, true);
}
@mixin btnNoticeable($bg: $colorBodyBg, $fg: $colorBodyFg) {
@include containerSubtle($bg, $fg);
@include background-image(linear-gradient(lighten($bg, 20%), $bg));
&:not(.disabled):hover {
// No longer should be used; use btnSubtle instead
//@include containerSubtle($bg, $fg, true);
//@include background-image(linear-gradient(lighten($bg, 20%), $bg));
/* &:not(.disabled):hover {
@include background-image(linear-gradient(lighten($bg, 30%), lighten($bg, 10%)));
}
}*/
}
@mixin boxIncised($sVal: 0.6) {
@ -166,8 +220,8 @@
border: 1px solid $c;
}
@mixin boxShdwSubtle($sVal: 0.3) {
@include box-shadow(rgba(black, $sVal) 0 1px 3px);
@mixin boxShdwSubtle($sVal: 0.2) {
@include box-shadow(rgba(black, $sVal) 0 1px 2px);
}
@mixin boxShdwLarge($sVal: 0.7) {
@ -194,13 +248,15 @@
}
@mixin invokeMenu($baseColor) {
/*
@mixin invokeMenu($baseColor: $colorBodyFg) {
$c: $baseColor;
color: $c;
&:hover {
color: lighten($c, $ltGamma);
}
}
*/
@mixin menuUlReset() {
margin: 0;

View File

@ -19,37 +19,97 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$pad: $interiorMargin * 2;
$baseRatio: 1.5;
$pad: $interiorMargin * $baseRatio;
/*********************************** TYPE STYLES */
.t-btn {
cursor: pointer;
/******* LAYOUT AND SIZING */
.btn,
.l-btn {
line-height: 1.25em;
padding: 0 $pad;
text-decoration: none;
&.lg,
&.create-btn {
$h: $ueTopBarH - $interiorMargin;
height: $h;
line-height: $h;
padding: 0 $pad * 3;
}
&.create-btn {
.menu {
margin-left: $pad * -1;
}
>.ui-symbol {
font-size: 1.1em;
}
}
&.sm {
padding: 0 $pad / $baseRatio;
}
&.vsm {
padding: 0 ($pad / $baseRatio) / 2;
}
}
/*********************************** STYLE STYLES */
.btn,
.s-btn {
$base: lighten($colorBodyBg, 20%);
$base: lighten($colorBodyBg, 20%); // Moved to s-btn
@include border-radius($controlCr);
@include box-sizing(border-box);
@include text-shadow(rgba(black, 0.3) 0 1px 1px);
cursor: pointer;
line-height: 1.2em;
padding: 0 $pad;
text-decoration: none;
&.major {
$bg: $colorKey;
@include btnSubtle($bg);
$fg: lighten($bg, 50%);
color: $fg;
&:hover {
@include btnSubtle(lighten($bg, 5%), $fg);
//color: $fg;
}
.invoke-menu {
color: $fg;
}
}
&.subtle {
@include btnSubtle($base, lighten($base, 40%));
}
&.very-subtle,
&.s-very-subtle {
@include containerSubtle($colorBodyBg, $colorBodyFg, true);
&.paused {
@include containerSubtle($colorPausedBg, $colorPausedFg, true);
.icon:before {
content:"\0000EF";
}
}
}
}
.icon-btn,
.s-icon-btn {
@extend .s-btn;
font-size: 1.2em;
font-size: 1em;
.icon {
color: $colorKey;
}
&.paused {
.icon {
color: $colorPausedFg;
}
}
&:not(.disabled):hover .icon {
color: lighten($colorKey, $ltGamma);
&:not(.disabled) {
&:not(.paused) {
&:hover {
.icon {
color: lighten($colorKey, $ltGamma);
}
}
}
}
&.labeled {
@ -61,12 +121,30 @@ $pad: $interiorMargin * 2;
margin-left: $interiorMargin;
}
}
&.pause-play {
&.paused {
@include pulse(500ms);
}
.icon:before {
content:"\0000F1";
}
}
&.show-thumbs {
.icon:before {
content:"\000039";
}
}
}
/*********************************** LAYOUT STYLES */
span.btn,
span.btn span,
span.l-btn,
span.l-btn span,
a.btn,
a.btn span,
a.l-btn,
a.l-btn span {
display: inline-block;

View File

@ -19,7 +19,8 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
.control {
/*.control {
// UNUSED?
&.view-control {
.icon {
display: inline-block;
@ -45,10 +46,10 @@
}
}
}
}
}*/
.accordion {
$accordionHeadH: 18px;
$accordionHeadH: 18px;
margin-top: $interiorMargin;
&:first-child {
margin-top: 0;
@ -56,16 +57,20 @@
.accordion-head {
$op: 0.2;
@include border-radius($basicCr * 0.75);
@include box-sizing("border-box");
@include box-sizing("border-box");
background: rgba($colorBodyFg, $op);
cursor: pointer;
font-size: 0.75em;
line-height: $accordionHeadH;
line-height: $accordionHeadH;
margin-bottom: $interiorMargin;
padding: 0 $interiorMargin;
position: absolute;
top: 0; right: 0; bottom: auto; left: 0;
width: auto; height: $accordionHeadH;
top: 0;
right: 0;
bottom: auto;
left: 0;
width: auto;
height: $accordionHeadH;
text-transform: uppercase;
&:hover {
background: rgba($colorBodyFg, $op * 2);
@ -84,79 +89,14 @@
content: "v";
}
}
.accordion-contents {
position: absolute;
top: $accordionHeadH + $interiorMargin; right: 0; bottom: 0; left: 0;
overflow-y: auto;
overflow-x: hidden;
}
}
.btn {
$base: lighten($colorBodyBg, 20%); // Moved to s-btn
$p: 10px; // Moved to s-btn
@include border-radius($controlCr); // Moved to s-btn
@include box-sizing(border-box); // Moved to s-btn
@include text-shadow(rgba(black, 0.3) 0 1px 1px); // Moved to s-btn
// display: inline-block;
// margin-right: 10px;
padding: 0 ($interiorMargin * 2); // Moved to s-btn
text-decoration: none; // Moved to s-btn
&.create-btn {
$h: $ueTopBarH - $interiorMargin; //$btnStdH * 1.5;;
$p: $p * 2.25;
height: $h;
line-height: $h;
//font-size: 1.1em;
padding: 0 $p;
.menu {
margin-left: $p * -1;
}
.ui-symbol.major {
font-size: 1.1em;
}
}
&.major {
$bg: $colorKey;
@include btnNoticeable($bg);
$fg: lighten($bg, 50%);
color: $fg;
&:hover {
@include btnNoticeable(lighten($bg, 5%));
color: $fg;
}
.invoke-menu {
color: $fg;
}
}
&.normal {
padding: $p * 0.5 $p * 0.7;
}
&.outline {
&:hover {
background: rgba(#fff, 0.1);
}
}
&.subtle {
@include btnSubtle($base, lighten($base, 40%));
}
&.very-subtle {
@include btnSubtle($colorBodyBg, lighten($colorBodyBg, 50%));
}
&.lg {
@include border-radius($controlCr * 1.5);
font-size: 1.2em;
padding: 7px 25px;
}
&.icon-btn {
.icon {
color: $colorKey;
}
&:not(.disabled):hover .icon {
color: lighten($colorKey, $ltGamma);
}
.accordion-contents {
position: absolute;
top: $accordionHeadH + $interiorMargin;
right: 0;
bottom: 0;
left: 0;
overflow-y: auto;
overflow-x: hidden;
}
}
@ -166,12 +106,12 @@
.btn-set,
.t-btn {
display: inline-block;
// margin-left: $interiorMargin;
// margin-left: $interiorMargin;
}
.btn,
.t-btn {
&:first-child {
// margin-left: 0;
// margin-left: 0;
}
}
}
@ -199,6 +139,20 @@
}
}
.l-local-controls {
// Control shown when hovering over an object, like plots and imagery
// Default position is upper right
$p: $interiorMargin;
position: absolute;
top: $p;
right: $p;
z-index: 5;
}
.s-local-controls {
font-size: 0.7rem;
}
.btn-set {
// Buttons that have a very tight conceptual grouping - no internal space between them.
display: inline-block;
@ -230,8 +184,8 @@
height: $h;
line-height: $h;
.icon:not(.invoke-menu) {
// position: relative;
// top: -0.04em;
// position: relative;
// top: -0.04em;
font-size: 150%;
vertical-align: middle;
}
@ -318,37 +272,43 @@ label.checkbox.custom {
.btn-menu {
$h: 20px;
$p: $interiorMargin * 2;
$p: $interiorMarginSm * 2;
$c: $colorBodyFg;
@include btnSubtle($colorBodyBg);
height: $h;
line-height: $h;
&.dropdown {
// padding-left: $p;
padding-left: $p;
padding-right: $p;
}
/* height: $h;
line-height: $h;
&.dropdown {
padding-left: $p;
padding-right: $p;
}*/
&:not(.disabled):hover {
color: lighten($c, 20%);
}
&.btn-invoke-menu {
$c: $colorKey;
color: $c;
padding: 0 5px;
&:hover {
color: lighten($c, 10%);
}
/* &.context-available {
// An element like the invoke-menu triangle;
// Indicates that this element has a dropdown menu available;
// Currently unused
$c: $colorKey;
color: $c;
padding: 0 5px;
&:hover {
color: lighten($c, 10%);
}
}*/
span.l-click-area {
// In markup, this element should not enclose anything.
@extend .abs;
}
span.l-click-area {
// In markup, this element should not enclose anything.
@extend .abs;
}
.type-icon {
margin-right: $interiorMargin;
//margin-right: $interiorMargin;
}
.name {
margin-left: $interiorMargin;
}
.menu {
// margin-left: (-1 * $p);
@ -388,17 +348,23 @@ label.checkbox.custom {
}
}
.view-switcher {
@include trans-prop-nice-fade($controlFadeMs);
}
/******************************************************** OBJECT-HEADER */
.object-header {
display: inline-block;
font-size: 1em;
.title {
color: lighten($colorBodyFg, 40%);
}
.type-icon {
font-size: 1.5em;
margin-right: $interiorMargin;
vertical-align: middle;
.label {
.title-label {
color: lighten($colorBodyFg, 40%);
}
.type-icon {
font-size: 1.5em;
margin-right: $interiorMargin;
vertical-align: middle;
}
}
}
@ -412,86 +378,53 @@ label.checkbox.custom {
}
}
/******************************************************** VIEW-CONTROLS */
.view-controls .view-type {
$d: 20px;
$p: 5px;
@include border-radius($controlCr);
box-sizing: border-box;
display: inline-block;
margin-left: $interiorMargin;
height: $d;
line-height: $d;
padding-left: $p;
padding-right: $p;
&.cur {
background: lighten($colorBodyBg, $ltGamma);
}
}
.edit-mode .top-bar .control-set.edit-view-controls {
// Used in templates/edit-view-controls.html
margin-right: $interiorMargin * 10;
}
/******************************************************** SLIDERS */
.wrapper-slider {
position: relative;
}
.slider {
//$knobH: 70%; //14px;
$knobH: 100%; //14px;
$knobW: 12px;
$slotH: 80%;
$rangeO: 0.3;
$slotH: 50%;
.slot {
// @include border-radius($basicCr * .75);
@include sliderTrack();
height: auto;
height: $slotH;
width: auto;
position: absolute;
//top: ($knobH - $slotH) / 2;
top: (100% - $slotH)/2;
top: ($knobH - $slotH) / 2;
right: 0;
bottom: (100% - $slotH)/2;
bottom: auto;
left: 0;
z-index: 0;
.range {
background: rgba($colorKey, $rangeO);
cursor: ew-resize;
position: absolute;
top: 0;
right: auto;
bottom: 0;
left: auto;
height: auto;
width: auto;
z-index: 1;
&:hover {
background: rgba($colorKey, $rangeO + 0.2);
}
}
}
.knob {
@include btnSubtle();
@include controlGrippy(rgba(black, 0.3), vertical, 1px, solid);
@include border-radius(2px);
cursor: ew-resize;
position: absolute;
height: auto;
height: $knobH;
width: $knobW;
top: 0;
bottom: 0;
auto: 0;
bottom: auto;
left: auto;
z-index: 2;
&.knob-l { margin-left: $knobW / -2; }
&.knob-r { margin-right: $knobW / -2; }
&:before {
top: 1px;
bottom: 3px;
//left: ($knobW / 2) - 1;
//margin-left: -1px;
left: 45%;
left: ($knobW / 2) - 1;
}
}
.range {
background: rgba($colorKey, 0.6);
cursor: ew-resize;
position: absolute;
top: 0;
right: auto;
bottom: 0;
left: auto;
height: auto;
width: auto;
&:hover {
background: rgba($colorKey, 0.7);
}
}
}
@ -499,23 +432,23 @@ label.checkbox.custom {
/******************************************************** BROWSER ELEMENTS */
::-webkit-scrollbar {
@include sliderTrack();
height: $scrollbarTrackSize;
width: $scrollbarTrackSize;
@include sliderTrack();
height: $scrollbarTrackSize;
width: $scrollbarTrackSize;
}
::-webkit-scrollbar-thumb {
$bg: lighten($colorBodyBg, 10%);
@include background-image(linear-gradient(lighten($bg, 10%), lighten($bg, 5%) 20px));
@include border-radius(1px);
@include box-sizing(border-box);
@include boxShdwSubtle();
border-top: 1px solid lighten($bg, 20%);
&:hover {
@include background-image(linear-gradient(lighten($bg, 20%), lighten($bg, 15%) 20px));
}
$bg: lighten($colorBodyBg, 10%);
@include background-image(linear-gradient(lighten($bg, 10%), lighten($bg, 5%) 20px));
@include border-radius(1px);
@include box-sizing(border-box);
@include boxShdwSubtle();
border-top: 1px solid lighten($bg, 20%);
&:hover {
@include background-image(linear-gradient(lighten($bg, 20%), lighten($bg, 15%) 20px));
}
}
::-webkit-scrollbar-corner {
background: rgba(#000, 0.4);
background: rgba(#000, 0.4);
}

View File

@ -41,7 +41,7 @@
@include box-sizing(border-box);
border-top: 1px solid lighten($bg, 20%);
line-height: $menuLineH;
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 3) + $treeTypeIconW;
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
white-space: nowrap;
&:first-child {
border: none;
@ -168,7 +168,7 @@
position: absolute;
height: 200px;
width: 170px;
z-index: 59;
z-index: 70;
.context-menu-wrapper {
position: absolute;
height: 100%;

View File

@ -19,3 +19,86 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
.edit-main {
$handleD: 15px;
$cr: 5px;
.edit-corner,
.edit-handle {
position: absolute;
z-index: 2;
}
.edit-corner {
width: $handleD;
height: $handleD;
&.edit-resize-nw {
@include border-bottom-right-radius($cr);
cursor: nw-resize;
top: 0; left: 0;
}
&.edit-resize-se {
@include border-top-left-radius($cr);
cursor: se-resize;
bottom: 0; right: 0;
}
&.edit-resize-sw {
@include border-top-right-radius($cr);
cursor: sw-resize;
bottom: 0; left: 0;
}
}
.edit-handle {
top: $handleD; right: $handleD; bottom: $handleD; left: $handleD;
&.edit-move {
$m: 0; //$handleD;
cursor: move;
left: $m;
right: $m;
top: $m;
bottom: $m;
z-index: 1;
}
&.edit-resize-n {
top: 0px; bottom: auto;
height: $handleD;
cursor: n-resize;
}
&.edit-resize-e {
right: 0px; left: auto;
width: $handleD;
cursor: e-resize;
}
&.edit-resize-s {
bottom: 0px; top: auto;
height: $handleD;
cursor: s-resize;
}
&.edit-resize-w {
left: 0px; right: auto;
width: $handleD;
cursor: w-resize;
}
}
.frame.child-frame.panel {
&:hover {
@include boxShdwLarge();
border-color: $colorKey;
z-index: 2;
.view-switcher {
opacity: 1;
}
.edit-corner {
background-color: rgba($colorKey, 0.8);
&:hover {
background-color: rgba($colorKey, 1);
}
}
}
}
}

View File

@ -0,0 +1,171 @@
.l-image-main-wrapper,
.l-image-main,
.l-image-main-controlbar,
.l-image-main-controlbar .left,
.l-image-main-controlbar .right,
.l-image-thumbs-wrapper {
@include absPosDefault(0, false);
}
/*************************************** MAIN LAYOUT */
.l-image-main-wrapper {
//@include test();
@if $enableImageryThumbs == true {
bottom: $interiorMargin*2 + $imageThumbsWrapperH;
}
min-height: 100px;
min-width: 150px;
.l-image-main {
background-color: rgba(#fff, 0.1);
bottom: $imageMainControlBarH + $interiorMargin;
}
.l-image-main-controlbar {
top: auto;
height: $imageMainControlBarH;
}
}
.l-image-thumbs-wrapper {
//@include test(red);
top: auto;
height: $imageThumbsWrapperH;
}
.l-date,
.l-time,
.l-timezone {
display: inline-block;
}
/*************************************** MAIN IMAGE */
.l-image-main,
.l-image-thumb-item .l-thumb {
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.l-image-main {
cursor: crosshair;
}
.l-image-main-controlbar {
//@include test();
font-size: 0.8em;
line-height: $imageMainControlBarH;
.left, .right {
direction: rtl;
overflow: hidden;
}
.left {
//@include test(red);
text-align: left;
width: 75% !important;
}
.right {
//@include test(green);
min-width: 40px;
width: 25% !important;
z-index: 2;
}
.l-date,
.l-time {
color: #fff;
}
.l-mag {
direction: ltr;
display: inline-block;
//white-space: nowrap;
&:before {
content: "\000049";
}
}
.s-mag {
color: darken($colorBodyFg, 20%);
}
.l-btn.show-thumbs {
display: none;
}
}
.s-image-main {
border: 1px solid transparent;
&.paused {
border-color: $colorPausedBg;
}
}
/*************************************** THUMBS */
.l-image-thumbs-wrapper {
//@include test(green);
direction: rtl;
overflow-x: auto;
overflow-y: hidden;
padding-bottom: $interiorMargin;
white-space: nowrap;
z-index: 70;
}
.l-image-thumb-item {
@include single-transition(background-color, 0.25s);
@include box-sizing(border-box);
padding: 1px;
position: relative;
.l-thumb,
.l-date,
.l-time {
display: inline-block;
}
.l-date,
.l-time {
padding: 2px 3px;
}
cursor: pointer;
direction: ltr;
display: inline-block;
font-size: 0.8em;
margin-left: $interiorMarginSm;
text-align: left;
width: $imageThumbsD + $imageThumbPad*2;
white-space: normal;
&:hover {
background: rgba(#fff, 0.2);
.l-date,
.l-time {
color: #fff;
}
}
&.selected {
background: $colorKeySelectedBg;
.l-date,
.l-time {
color: #fff;
}
}
.l-thumb {
background-color: rgba(#fff, 0.1);
height: $imageThumbsD;
width: $imageThumbsD;
margin-top: 0;
}
}
/*************************************** WHEN IN FRAME */
.frame .t-imagery {
.l-image-main-wrapper {
bottom: 0;
.l-image-main-controlbar {
font-size: 0.7em;
}
@if $enableImageryThumbs == true {
.l-btn.show-thumbs {
display: inline-block;
}
}
}
.l-image-thumbs-wrapper {
display: none;
}
}

View File

@ -0,0 +1,44 @@
.l-time-display {
$transTime: 200ms;
// Layout
&:hover {
.l-btn.control {
//display: inline-block;
opacity: 1;
}
}
.l-elem-wrapper {
position: relative;
}
.l-elem {
display: inline-block;
}
&.l-timer {
.l-elem.l-value {
@include trans-prop-nice(left, $transTime);
position: absolute;
left: 0;
z-index: 1;
}
&:hover .l-elem.l-value {
left: 20px;
}
}
// Look-and-feel
.l-elem {
.value.active,
&.value.active {
color: $colorKeyFg;
}
}
.l-btn.control {
@include trans-prop-nice-fade($transTime);
//display: none;
opacity: 0;
font-size: 0.9em;
line-height: 1em;
}
}

View File

@ -19,18 +19,13 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
input[type="text"],
input[type="date"] {
input[type="text"] {
@include nice-input();
@include input-placeholder {
color: darken($colorBodyFg, 10%);
font-style: italic;
}
&.filter {
&.ng-dirty {
// background: red;
}
}
&.filter {
&.ng-dirty {
// background: red;
}
}
&.numeric {
text-align: right;
}

View File

@ -21,17 +21,15 @@
*****************************************************************************/
//************************************************* LAYOUT
$infoBubbleFg: #666;
$infoBubbleBg: #ddd;
.l-infobubble-wrapper {
$arwSize: 5px;
@include box-shadow(rgba(black, 0.4) 0 1px 5px);
position: absolute;
z-index: 70;
position: relative;
z-index: 50;
.l-infobubble {
display: inline-block;
max-width: 250px;
min-width: $bubbleMinW;
max-width: $bubbleMaxW;
padding: 5px 10px;
&:before {
content:"";
@ -71,34 +69,30 @@ $infoBubbleBg: #ddd;
}
&.arw-left {
margin-left: $arwSize*2;
margin-left: $bubbleArwSize*2;
.l-infobubble::before {
right: 100%;
border-top: $arwSize solid transparent;
border-bottom: $arwSize solid transparent;
border-right: ($arwSize * 1.5) solid $infoBubbleBg;
@include triangle('left', $bubbleArwSize, 1.5, $colorInfoBubbleBg);
}
}
&.arw-right {
margin-right: $arwSize*2;
margin-right: $bubbleArwSize*2;
.l-infobubble::before {
left: 100%;
border-top: $arwSize solid transparent;
border-bottom: $arwSize solid transparent;
border-left: ($arwSize * 1.5) solid $infoBubbleBg;
@include triangle('right', $bubbleArwSize, 1.5, $colorInfoBubbleBg);
}
}
&.arw-top {
.l-infobubble::before {
top: $arwSize * 2;
top: $bubbleArwSize * 2;
}
}
&.arw-btm {
.l-infobubble::before {
bottom: $arwSize * 2;
bottom: $bubbleArwSize * 2;
}
}
@ -110,18 +104,32 @@ $infoBubbleBg: #ddd;
margin-left: -1 * $arwSize;
border-left: $arwSize solid transparent;
border-right: $arwSize solid transparent;
border-top: ($arwSize * 1.5) solid $infoBubbleBg;
border-top: ($arwSize * 1.5) solid $colorInfoBubbleBg;
}
}
.arw {
z-index: 2;
}
&.arw-up .arw.arw-down,
&.arw-down .arw.arw-up { display: none; }
}
//************************************************* LOOK AND FEEL
.l-thumbsbubble-wrapper {
.arw-up {
@include triangle('up', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
}
.arw-down {
@include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
}
}
.s-infobubble {
$emFg: darken($infoBubbleFg, 20%);
$emFg: darken($colorInfoBubbleFg, 20%);
@include border-radius($basicCr);
background: $infoBubbleBg;
color: $infoBubbleFg;
@include box-shadow(rgba(black, 0.4) 0 1px 5px);
background: $colorInfoBubbleBg;
color: $colorInfoBubbleFg;
font-size: 0.8rem;
.title {
color: $emFg;
@ -129,7 +137,7 @@ $infoBubbleBg: #ddd;
}
tr {
td {
border-top: 1px solid darken($infoBubbleBg, 10%);
border-top: 1px solid darken($colorInfoBubbleBg, 10%);
font-size: 0.9em;
}
&:first-child td {
@ -139,5 +147,9 @@ $infoBubbleBg: #ddd;
.value {
color: $emFg;
}
}
.s-thumbsbubble {
background: $colorThumbsBubbleBg;
color: $colorThumbsBubbleFg;
}

View File

@ -104,7 +104,7 @@
&.selected {
$cfg: lighten($colorItemSelected, 35%);
$cfgh: lighten($cfg, 30%);
@include btnNoticeable($colorItemSelected);
@include btnSubtle($colorItemSelected);
color: $cfg;
.item-type, .top-bar .icon:not(.alert) { color: $cfg }
.item-main .item-open { color: $cfg }

View File

@ -75,8 +75,8 @@ ul.tree {
.title-label {
@include absPosDefault();
display: block;
left: $runningItemW + ($interiorMargin * 2);
// right: $treeContextTriggerW + $interiorMargin; //Disabling as context trigger not being used
left: $runningItemW + ($interiorMargin);
//right: $treeContextTriggerW + $interiorMargin;
overflow: hidden;
text-overflow: ellipsis;
// height: $menuLineH;
@ -99,7 +99,7 @@ ul.tree {
&.selected {
$c: #fff;
background: #005177;
background: $colorKeySelectedBg;
color: $c;
.view-control {
color: $colorItemTreeIcon;
@ -124,16 +124,15 @@ ul.tree {
&:not(.loading) {
cursor: pointer;
// @include tree-item-hover();
}
.context-trigger {
$h: 0.9rem;
display: none;
//display: none;
top: -1px;
position: absolute;
right: $interiorMarginSm;
.btn-invoke-menu {
.invoke-menu {
font-size: 0.75em;
height: $h;
line-height: $h;

View File

@ -27,6 +27,7 @@
border: 1px solid $bc;
&:hover {
border-color: lighten($bc, 10%);
z-index: 2;
}
.contents {
// overflow: hidden;
@ -46,12 +47,25 @@
bottom: $myM;
left: $myM;
}
}
.edit-main .frame.child-frame.panel {
&:hover {
border-color: $colorKey;
@include boxShdwLarge();
&.frame-template {
// Hide the view switcher by default when it's in an element that's in a frame context
// Frame template is used because we need to target the lowest nested frame
// This has the effect of hiding the view switcher in nested frames in edit mode, which is desirable currently (as it's non-functional)
.view-switcher {
//display: none;
opacity: 0;
z-index: 10;
}
&:hover .view-switcher {
// Show the view switcher on frame hover
//display: inline-block !important;
opacity: 1;
}
}
.view-switcher {
// Hide the name when the view switcher is in a frame context
.name {
display: none;
}
}
}

View File

@ -70,23 +70,19 @@
&.abs {
text-wrap: none;
white-space: nowrap;
&.left,
.left {
width: 45%;
right: auto;
}
&.right,
.right {
width: 45%;
left: auto;
right: 0;
text-align: right;
.icon.major {
margin-left: $interiorMargin * 3;
}
// .icon.major {
// margin-left: $interiorMargin;
// }
}
&.left,
.left {
width: 45% !important;
right: auto !important;
}
&.right,
.right {
width: 45% !important;
left: auto !important;
text-align: right;
.icon.major {
margin-left: $interiorMargin * 3;
}
}
}

View File

@ -19,7 +19,7 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<a class="t-btn l-btn s-btn s-icon-btn s-very-subtle key-{{parameters.action.getMetadata().key}}"
<a class="btn s-btn s-icon-btn s-very-subtle key-{{parameters.action.getMetadata().key}}"
ng-class="{ labeled: parameters.labeled }"
title="{{parameters.action.getMetadata().description}}"
ng-click="parameters.action.perform()">

View File

@ -21,25 +21,29 @@
-->
<span ng-controller="ViewSwitcherController">
<div class="menu-element btn icon-btn very-subtle btn-menu dropdown click-invoke"
ng-if="view.length > 1"
ng-controller="ClickAwayController as toggle">
<div
class="view-switcher menu-element btn btn-menu dropdown click-invoke"
ng-if="view.length > 1"
ng-controller="ClickAwayController as toggle"
>
<span class="l-click-area" ng-click="toggle.toggle()"></span>
<span
class="l-click-area"
ng-click="toggle.toggle()"
title="{{ngModel.selected.name}}"
></span>
<span class="ui-symbol icon type-icon">{{ngModel.selected.glyph}}</span>
<span>{{ngModel.selected.name}}</span>
<span class='ui-symbol icon invoke-menu'>v</span>
<span class="name">{{ngModel.selected.name}}</span>
<span class='ui-symbol invoke-menu'>v</span>
<div class="menu dropdown" ng-show="toggle.isActive()">
<ul>
<li ng-repeat="option in view">
<a href="" ng-click="ngModel.selected = option; toggle.setState(false)">
<span class="ui-symbol type-icon icon">
{{option.glyph}}
</span>
{{option.name}}
<a ng-click="ngModel.selected = option; toggle.setState(false)">
<span class="ui-symbol type-icon icon">{{option.glyph}}</span>
{{option.name}}
</a>
</li>
</ul>

View File

@ -1,20 +1,50 @@
{
"extensions": {
"types": [
"templates": [
{
"key": "infobubble",
"name": "Info Bubble",
"glyph": "\u00EA",
"description": "Static markup for info bubbles",
"features": [ "creation" ]
"key": "info-table",
"templateUrl": "info-table.html"
},
{
"key": "info-bubble",
"templateUrl": "info-bubble.html"
}
],
"views": [
"containers": [
{
"templateUrl": "infobubble.html",
"name": "Info Bubble",
"type": "infobubble",
"key": "infobubble"
"key": "bubble",
"templateUrl": "bubble.html",
"attributes": [ "bubbleTitle", "bubbleLayout" ],
"alias": "bubble"
}
],
"gestures": [
{
"key": "info",
"implementation": "gestures/InfoGesture.js",
"depends": [
"$timeout",
"infoService",
"INFO_HOVER_DELAY"
]
}
],
"services": [
{
"key": "infoService",
"implementation": "services/InfoService.js",
"depends": [
"$compile",
"$document",
"$window",
"$rootScope"
]
}
],
"constants": [
{
"key": "INFO_HOVER_DELAY",
"value": 500
}
]
}

View File

@ -0,0 +1,9 @@
<div class="t-infobubble s-infobubble l-infobubble-wrapper {{bubble.bubbleLayout}}">
<div class="l-infobubble">
<div ng-show="bubble.bubbleTitle.length > 0"
class="title">
{{bubble.bubbleTitle}}
</div>
<span ng-transclude></span>
</div>
</div>

View File

@ -0,0 +1,7 @@
<mct-container key="bubble"
bubble-title="{{parameters.title}}"
bubble-layout="{{parameters.layout}}">
<mct-include key="info-table"
ng-model="ngModel">
</mct-include>
</mct-container>

View File

@ -0,0 +1,8 @@
<table>
<tr ng-repeat="property in ngModel">
<td class="label">{{property.name}}</td>
<td title="{{property.value}}" class="value align-{{property.align}}">
{{property.value}}
</td>
</tr>
</table>

View File

@ -19,12 +19,17 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@import "compass";
@import "compass/css3";
@import "compass/css3/border-radius";
@import "compass/css3/opacity";
@import "compass/utilities";
@import "constants";
@import "mixins";
@import "plots/plots-main";
/*global define*/
define({
BUBBLE_TEMPLATE: "<mct-container key=\"bubble\" " +
"bubble-title=\"{{bubbleTitle}}\" " +
"bubble-layout=\"{{bubbleLayout}}\">" +
"<mct-include key=\"bubbleTemplate\" ng-model=\"bubbleModel\">" +
"</mct-include>" +
"</mct-container>",
// Pixel offset for bubble, to align arrow position
BUBBLE_OFFSET: [ 0, -26 ],
// Max width and margins allowed for bubbles; defined in /platform/commonUI/general/res/sass/_constants.scss
BUBBLE_MARGIN_LR: 10,
BUBBLE_MAX_WIDTH: 300
});

View File

@ -0,0 +1,121 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
[],
function () {
"use strict";
/**
* The `info` gesture displays domain object metadata in a
* bubble on hover.
*
* @constructor
* @param $timeout Angular's `$timeout`
* @param {InfoService} infoService a service which shows info bubbles
* @param {number} DELAY delay, in milliseconds, before bubble appears
* @param element jqLite-wrapped DOM element
* @param {DomainObject} domainObject the domain object for which to
* show information
*/
function InfoGesture($timeout, infoService, DELAY, element, domainObject) {
var dismissBubble,
pendingBubble,
mousePosition,
scopeOff;
function trackPosition(event) {
// Record mouse position, so bubble can be shown at latest
// mouse position (not just where the mouse entered)
mousePosition = [ event.clientX, event.clientY ];
}
function hideBubble() {
// If a bubble is showing, dismiss it
if (dismissBubble) {
dismissBubble();
element.off('mouseleave', hideBubble);
dismissBubble = undefined;
}
// If a bubble will be shown on a timeout, cancel that
if (pendingBubble) {
$timeout.cancel(pendingBubble);
element.off('mousemove', trackPosition);
element.off('mouseleave', hideBubble);
pendingBubble = undefined;
}
// Also clear mouse position so we don't have a ton of tiny
// arrays allocated while user mouses over things
mousePosition = undefined;
}
function showBubble(event) {
trackPosition(event);
// Also need to track position during hover
element.on('mousemove', trackPosition);
// Show the bubble, after a suitable delay (if mouse has
// left before this time is up, this will be canceled.)
pendingBubble = $timeout(function () {
dismissBubble = infoService.display(
"info-table",
domainObject.getModel().name,
domainObject.useCapability('metadata'),
mousePosition
);
element.off('mousemove', trackPosition);
pendingBubble = undefined;
}, DELAY);
element.on('mouseleave', hideBubble);
}
// Show bubble (on a timeout) on mouse over
element.on('mouseenter', 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.
* @memberof InfoGesture
* @method
*/
destroy: function () {
// Dismiss any active bubble...
hideBubble();
// ...and detach listeners
element.off('mouseenter', showBubble);
scopeOff();
}
};
}
return InfoGesture;
}
);

View File

@ -0,0 +1,95 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
['../InfoConstants'],
function (InfoConstants) {
"use strict";
var BUBBLE_TEMPLATE = InfoConstants.BUBBLE_TEMPLATE,
OFFSET = InfoConstants.BUBBLE_OFFSET;
/**
* Displays informative content ("info bubbles") for the user.
* @constructor
*/
function InfoService($compile, $document, $window, $rootScope) {
function display(templateKey, title, content, position) {
var body = $document.find('body'),
scope = $rootScope.$new(),
winDim = [$window.innerWidth, $window.innerHeight],
bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR + InfoConstants.BUBBLE_MAX_WIDTH,
goLeft = position[0] > (winDim[0] - bubbleSpaceLR),
goUp = position[1] > (winDim[1] / 2),
bubble;
// Pass model & container parameters into the scope
scope.bubbleModel = content;
scope.bubbleTemplate = templateKey;
scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' +
(goLeft ? 'arw-right' : 'arw-left');
scope.bubbleTitle = title;
// Create the context menu
bubble = $compile(BUBBLE_TEMPLATE)(scope);
// Position the bubble
bubble.css('position', 'absolute');
if (goLeft) {
bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
} else {
bubble.css('left', position[0] + OFFSET[0] + 'px');
}
if (goUp) {
bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
} else {
bubble.css('top', position[1] + OFFSET[1] + 'px');
}
// Add the menu to the body
body.append(bubble);
// Return a function to dismiss the bubble
return function () { bubble.remove(); };
}
return {
/**
* Display an info bubble at the specified location.
* @param {string} templateKey template to place in bubble
* @param {string} title title for the bubble
* @param {*} content content to pass to the template, via
* `ng-model`
* @param {number[]} x,y position of the info bubble, in
* pixel coordinates.
* @returns {Function} a function that may be invoked to
* dismiss the info bubble
*/
display: display
};
}
return InfoService;
}
);

View File

@ -0,0 +1,157 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
['../../src/gestures/InfoGesture'],
function (InfoGesture) {
"use strict";
describe("The info gesture", function () {
var mockTimeout,
mockInfoService,
testDelay = 12321,
mockElement,
mockDomainObject,
mockScope,
mockOff,
testMetadata,
mockPromise,
mockHide,
gesture;
function fireEvent(evt, value) {
mockElement.on.calls.forEach(function (call) {
if (call.args[0] === evt) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockTimeout = jasmine.createSpy('$timeout');
mockTimeout.cancel = jasmine.createSpy('cancel');
mockInfoService = jasmine.createSpyObj(
'infoService',
[ 'display' ]
);
mockElement = jasmine.createSpyObj(
'element',
[ 'on', 'off', 'scope', 'css' ]
);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
[ 'getId', 'getCapability', 'useCapability', 'getModel' ]
);
mockScope = jasmine.createSpyObj('$scope', [ '$on' ]);
mockOff = jasmine.createSpy('$off');
testMetadata = [ { name: "Test name", value: "Test value" } ];
mockPromise = jasmine.createSpyObj('promise', ['then']);
mockHide = jasmine.createSpy('hide');
mockDomainObject.getModel.andReturn({ name: "Test Object" });
mockDomainObject.useCapability.andCallFake(function (c) {
return (c === 'metadata') ? testMetadata : undefined;
});
mockElement.scope.andReturn(mockScope);
mockScope.$on.andReturn(mockOff);
mockTimeout.andReturn(mockPromise);
mockInfoService.display.andReturn(mockHide);
gesture = new InfoGesture(
mockTimeout,
mockInfoService,
testDelay,
mockElement,
mockDomainObject
);
});
it("listens for mouseenter on the representation", function () {
expect(mockElement.on)
.toHaveBeenCalledWith('mouseenter', jasmine.any(Function));
});
it("displays an info bubble on a delay after mouseenter", function () {
fireEvent("mouseenter", { clientX: 1977, clientY: 42 });
expect(mockTimeout)
.toHaveBeenCalledWith(jasmine.any(Function), testDelay);
mockTimeout.mostRecentCall.args[0]();
expect(mockInfoService.display).toHaveBeenCalledWith(
jasmine.any(String),
"Test Object",
testMetadata,
[ 1977, 42 ]
);
});
it("does not display info bubble if mouse leaves too soon", function () {
fireEvent("mouseenter", { clientX: 1977, clientY: 42 });
fireEvent("mouseleave", { clientX: 1977, clientY: 42 });
expect(mockTimeout.cancel).toHaveBeenCalledWith(mockPromise);
expect(mockInfoService.display).not.toHaveBeenCalled();
});
it("hides a shown bubble when mouse leaves", function () {
fireEvent("mouseenter", { clientX: 1977, clientY: 42 });
mockTimeout.mostRecentCall.args[0]();
expect(mockHide).not.toHaveBeenCalled(); // verify precondition
fireEvent("mouseleave", {});
expect(mockHide).toHaveBeenCalled();
});
it("tracks mouse position", function () {
fireEvent("mouseenter", { clientX: 1977, clientY: 42 });
fireEvent("mousemove", { clientX: 1999, clientY: 11 });
fireEvent("mousemove", { clientX: 1984, clientY: 11 });
mockTimeout.mostRecentCall.args[0]();
// Should have displayed at the latest observed mouse position
expect(mockInfoService.display).toHaveBeenCalledWith(
jasmine.any(String),
"Test Object",
testMetadata,
[ 1984, 11 ]
);
});
it("hides shown bubbles when destroyed", function () {
fireEvent("mouseenter", { clientX: 1977, clientY: 42 });
mockTimeout.mostRecentCall.args[0]();
expect(mockHide).not.toHaveBeenCalled(); // verify precondition
gesture.destroy();
expect(mockHide).toHaveBeenCalled();
});
it("detaches listeners when destroyed", function () {
fireEvent("mouseenter", { clientX: 1977, clientY: 42 });
gesture.destroy();
mockElement.on.calls.forEach(function (call) {
expect(mockElement.off).toHaveBeenCalledWith(
call.args[0],
call.args[1]
);
});
});
});
}
);

View File

@ -0,0 +1,131 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
['../../src/services/InfoService', '../../src/InfoConstants'],
function (InfoService, InfoConstants) {
"use strict";
describe("The info service", function () {
var mockCompile,
mockDocument,
testWindow,
mockRootScope,
mockCompiledTemplate,
testScope,
mockBody,
mockElement,
service;
beforeEach(function () {
mockCompile = jasmine.createSpy('$compile');
mockDocument = jasmine.createSpyObj('$document', ['find']);
testWindow = { innerWidth: 1000, innerHeight: 100 };
mockRootScope = jasmine.createSpyObj('$rootScope', ['$new']);
mockCompiledTemplate = jasmine.createSpy('template');
testScope = {};
mockBody = jasmine.createSpyObj('body', ['append']);
mockElement = jasmine.createSpyObj('element', ['css', 'remove']);
mockDocument.find.andCallFake(function (tag) {
return tag === 'body' ? mockBody : undefined;
});
mockCompile.andReturn(mockCompiledTemplate);
mockCompiledTemplate.andReturn(mockElement);
mockRootScope.$new.andReturn(testScope);
service = new InfoService(
mockCompile,
mockDocument,
testWindow,
mockRootScope
);
});
it("creates elements and appends them to the body to display", function () {
service.display('', '', {}, [0, 0]);
expect(mockBody.append).toHaveBeenCalledWith(mockElement);
});
it("provides a function to remove displayed info bubbles", function () {
var fn = service.display('', '', {}, [0, 0]);
expect(mockElement.remove).not.toHaveBeenCalled();
fn();
expect(mockElement.remove).toHaveBeenCalled();
});
describe("depending on mouse position", function () {
// Positioning should vary based on quadrant in window,
// which is 1000 x 100 in this test case.
it("displays from the top-left in the top-left quadrant", function () {
service.display('', '', {}, [250, 25]);
expect(mockElement.css).toHaveBeenCalledWith(
'left',
(250 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
);
expect(mockElement.css).toHaveBeenCalledWith(
'top',
(25 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
);
});
it("displays from the top-right in the top-right quadrant", function () {
service.display('', '', {}, [700, 25]);
expect(mockElement.css).toHaveBeenCalledWith(
'right',
(300 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
);
expect(mockElement.css).toHaveBeenCalledWith(
'top',
(25 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
);
});
it("displays from the bottom-left in the bottom-left quadrant", function () {
service.display('', '', {}, [250, 70]);
expect(mockElement.css).toHaveBeenCalledWith(
'left',
(250 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
);
expect(mockElement.css).toHaveBeenCalledWith(
'bottom',
(30 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
);
});
it("displays from the bottom-right in the bottom-right quadrant", function () {
service.display('', '', {}, [800, 60]);
expect(mockElement.css).toHaveBeenCalledWith(
'right',
(200 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
);
expect(mockElement.css).toHaveBeenCalledWith(
'bottom',
(40 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
);
});
});
});
}
);

View File

@ -0,0 +1,4 @@
[
"gestures/InfoGesture",
"services/InfoService"
]

View File

@ -12,6 +12,11 @@
"implementation": "CompositionMutabilityPolicy.js",
"message": "Objects of this type cannot be modified."
},
{
"category": "composition",
"implementation": "CompositionModelPolicy.js",
"message": "Objects of this type cannot contain other objects."
},
{
"category": "action",
"implementation": "ComposeActionPolicy.js",

View File

@ -0,0 +1,28 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* Policy allowing composition only for domain object types which
* have a composition property.
*/
function CompositionModelPolicy() {
return {
/**
* Is the type identified by the candidate allowed to
* contain the type described by the context?
*/
allow: function (candidate, context) {
return Array.isArray(
(candidate.getInitialModel() || {}).composition
);
}
};
}
return CompositionModelPolicy;
}
);

View File

@ -0,0 +1,26 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/CompositionModelPolicy"],
function (CompositionModelPolicy) {
"use strict";
describe("The composition model policy", function () {
var mockType,
policy;
beforeEach(function () {
mockType = jasmine.createSpyObj('type', ['getInitialModel']);
policy = new CompositionModelPolicy();
});
it("only allows composition for types which will have a composition property", function () {
mockType.getInitialModel.andReturn({});
expect(policy.allow(mockType)).toBeFalsy();
mockType.getInitialModel.andReturn({ composition: [] });
expect(policy.allow(mockType)).toBeTruthy();
});
});
}
);

View File

@ -35,7 +35,7 @@ define(
policy = new CompositionMutabilityPolicy();
});
it("only allows composition for types which will have a composition capability", function () {
it("only allows composition for types which can be created/modified", function () {
expect(policy.allow(mockType)).toBeFalsy();
mockType.hasFeature.andReturn(true);
expect(policy.allow(mockType)).toBeTruthy();

View File

@ -1,6 +1,7 @@
[
"CapabilityTable",
"ComposeActionPolicy",
"CompositionModelPolicy",
"CompositionMutabilityPolicy",
"CompositionPolicy",
"ContainmentTable"

View File

@ -165,6 +165,10 @@
"implementation": "capabilities/PersistenceCapability.js",
"depends": [ "persistenceService", "PERSISTENCE_SPACE" ]
},
{
"key": "metadata",
"implementation": "capabilities/MetadataCapability.js"
},
{
"key": "mutation",
"implementation": "capabilities/MutationCapability.js",

View File

@ -0,0 +1,92 @@
/*global define*/
define(
['moment'],
function (moment) {
"use strict";
/**
* A piece of information about a domain object.
* @typedef {Object} MetadataProperty
* @property {string} name the human-readable name of this property
* @property {string} value the human-readable value of this property,
* for this specific domain object
*/
var TIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
/**
* Implements the `metadata` capability of a domain object, providing
* properties of that object for display.
*
* Usage: `domainObject.useCapability("metadata")`
*
* ...which will return an array of objects containing `name` and
* `value` properties describing that domain object (suitable for
* display.)
*
* @constructor
*/
function MetadataCapability(domainObject) {
var model = domainObject.getModel();
function hasDisplayableValue(metadataProperty) {
var t = typeof metadataProperty.value;
return (t === 'string' || t === 'number');
}
function formatTimestamp(timestamp) {
return typeof timestamp === 'number' ?
(moment.utc(timestamp).format(TIME_FORMAT) + " UTC") :
undefined;
}
function getProperties() {
var type = domainObject.getCapability('type');
function lookupProperty(typeProperty) {
return {
name: typeProperty.getDefinition().name,
value: typeProperty.getValue(model)
};
}
return (type ? type.getProperties() : []).map(lookupProperty);
}
function getCommonMetadata() {
var type = domainObject.getCapability('type');
// Note that invalid values will be filtered out later
return [
{
name: "Updated",
value: formatTimestamp(model.modified)
},
{
name: "Type",
value: type && type.getName()
},
{
name: "ID",
value: domainObject.getId()
}
];
}
function getMetadata() {
return getProperties().concat(getCommonMetadata())
.filter(hasDisplayableValue);
}
return {
/**
* Get metadata about this object.
* @returns {MetadataProperty[]} metadata about this object
*/
invoke: getMetadata
};
}
return MetadataCapability;
}
);

View File

@ -77,7 +77,8 @@ define(
// Get the object's model and clone it, so the
// mutator function has a temporary copy to work with.
var model = domainObject.getModel(),
clone = JSON.parse(JSON.stringify(model));
clone = JSON.parse(JSON.stringify(model)),
useTimestamp = arguments.length > 1;
// Function to handle copying values to the actual
function handleMutation(mutationResult) {
@ -94,8 +95,7 @@ define(
if (model !== result) {
copyValues(model, result);
}
model.modified = (typeof timestamp === 'number') ?
timestamp : now();
model.modified = useTimestamp ? timestamp : now();
}
// Report the result of the mutation

View File

@ -0,0 +1,101 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
['../../src/capabilities/MetadataCapability'],
function (MetadataCapability) {
"use strict";
describe("The metadata capability", function () {
var mockDomainObject,
mockType,
mockProperties,
testModel,
metadata;
function getCapability(key) {
return key === 'type' ? mockType : undefined;
}
function findValue(properties, name) {
var i;
for (i = 0; i < properties.length; i += 1) {
if (properties[i].name === name) {
return properties[i].value;
}
}
}
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getCapability', 'useCapability', 'getModel']
);
mockType = jasmine.createSpyObj(
'type',
['getProperties', 'getName']
);
mockProperties = ['a', 'b', 'c'].map(function (k) {
var mockProperty = jasmine.createSpyObj(
'property-' + k,
['getValue', 'getDefinition']
);
mockProperty.getValue.andReturn("Value " + k);
mockProperty.getDefinition.andReturn({ name: "Property " + k});
return mockProperty;
});
testModel = { name: "" };
mockDomainObject.getId.andReturn("Test id");
mockDomainObject.getModel.andReturn(testModel);
mockDomainObject.getCapability.andCallFake(getCapability);
mockDomainObject.useCapability.andCallFake(getCapability);
mockType.getProperties.andReturn(mockProperties);
mockType.getName.andReturn("Test type");
metadata = new MetadataCapability(mockDomainObject);
});
it("reads properties from the domain object model", function () {
metadata.invoke();
mockProperties.forEach(function (mockProperty) {
expect(mockProperty.getValue).toHaveBeenCalledWith(testModel);
});
});
it("reports type-specific properties", function () {
var properties = metadata.invoke();
expect(findValue(properties, 'Property a')).toEqual("Value a");
expect(findValue(properties, 'Property b')).toEqual("Value b");
expect(findValue(properties, 'Property c')).toEqual("Value c");
});
it("reports generic properties", function () {
var properties = metadata.invoke();
expect(findValue(properties, 'ID')).toEqual("Test id");
expect(findValue(properties, 'Type')).toEqual("Test type");
});
});
}
);

View File

@ -9,6 +9,7 @@
"capabilities/ContextualDomainObject",
"capabilities/CoreCapabilityProvider",
"capabilities/DelegationCapability",
"capabilities/MetadataCapability",
"capabilities/MutationCapability",
"capabilities/PersistenceCapability",
"capabilities/RelationshipCapability",

View File

@ -0,0 +1,24 @@
# Entanglement
Entanglement is the process of moving, copying, and linking domain objects
in such a way that their relationships are impossible to discern.
This bundle provides move, copy, and link functionality. Acheiving a state of
entanglement is left up to the end user.
## Services implement logic
Each method (move, copy, link) is implemented as a service, and each service
provides two functions: `validate` and `perform`.
`validate(object, parentCandidate)` returns true if the `object` can be
move/copy/linked into the `parentCandidate`'s composition.
`perform(object, parentObject)` move/copy/links the `object` into the
`parentObject`'s composition.
## Actions implement user interactions
Actions are used to expose move/copy/link to the user. They prompt for input
where necessary, and complete the actions.

View File

@ -0,0 +1,75 @@
{
"name": "Entanglement",
"description": "Tools to assist you in entangling the world of WARP.",
"configuration": {},
"extensions": {
"actions": [
{
"key": "move",
"name": "Move",
"description": "Move object to another location.",
"glyph": "f",
"category": "contextual",
"implementation": "actions/MoveAction.js",
"depends": ["locationService", "moveService"]
},
{
"key": "copy",
"name": "Duplicate",
"description": "Duplicate object to another location.",
"glyph": "+",
"category": "contextual",
"implementation": "actions/CopyAction.js",
"depends": ["locationService", "copyService"]
},
{
"key": "link",
"name": "Create Link",
"description": "Create Link to object in another location.",
"glyph": "\u00E8",
"category": "contextual",
"implementation": "actions/LinkAction.js",
"depends": ["locationService", "linkService"]
}
],
"components": [
],
"controllers": [
],
"capabilities": [
],
"services": [
{
"key": "moveService",
"name": "Move Service",
"description": "Provides a service for moving objects",
"implementation": "services/MoveService.js",
"depends": ["policyService", "linkService"]
},
{
"key": "linkService",
"name": "Link Service",
"description": "Provides a service for linking objects",
"implementation": "services/LinkService.js",
"depends": ["policyService"]
},
{
"key": "copyService",
"name": "Copy Service",
"description": "Provides a service for copying objects",
"implementation": "services/CopyService.js",
"depends": ["$q", "creationService", "policyService"]
},
{
"key": "locationService",
"name": "Location Service",
"description": "Provides a service for prompting a user for locations.",
"implementation": "services/LocationService.js",
"depends": ["dialogService"]
}
],
"licenses": [
]
}
}

View File

@ -0,0 +1,92 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* The CopyAction is available from context menus and allows a user to
* deep copy an object to another location of their choosing.
*
* @implements Action
*/
function CopyAction(locationService, copyService, context) {
var object,
newParent,
currentParent;
if (context.selectedObject) {
newParent = context.domainObject;
object = context.selectedObject;
} else {
object = context.domainObject;
}
currentParent = object
.getCapability('context')
.getParent();
return {
perform: function () {
if (newParent) {
return copyService
.perform(object, newParent);
}
var dialogTitle,
label,
validateLocation;
dialogTitle = [
"Duplicate ",
object.getModel().name,
" to a location"
].join("");
label = "Duplicate To";
validateLocation = function (newParent) {
return copyService
.validate(object, newParent);
};
return locationService.getLocationFromUser(
dialogTitle,
label,
validateLocation,
currentParent
).then(function (newParent) {
return copyService
.perform(object, newParent);
});
}
};
}
return CopyAction;
}
);

View File

@ -0,0 +1,89 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* The LinkAction is available from context menus and allows a user to
* link an object to another location of their choosing.
*
* @implements Action
*/
function LinkAction(locationService, linkService, context) {
var object,
newParent,
currentParent;
if (context.selectedObject) {
newParent = context.domainObject;
object = context.selectedObject;
} else {
object = context.domainObject;
}
currentParent = object
.getCapability('context')
.getParent();
return {
perform: function () {
if (newParent) {
return linkService
.perform(object, newParent);
}
var dialogTitle,
label,
validateLocation;
dialogTitle = [
"Link ",
object.getModel().name,
" to a new location"
].join("");
label = "Link To";
validateLocation = function (newParent) {
return linkService
.validate(object, newParent);
};
return locationService.getLocationFromUser(
dialogTitle,
label,
validateLocation,
currentParent
).then(function (newParent) {
return linkService
.perform(object, newParent);
});
}
};
}
return LinkAction;
}
);

View File

@ -0,0 +1,90 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* The MoveAction is available from context menus and allows a user to
* move an object to another location of their choosing.
*
* @implements Action
*/
function MoveAction(locationService, moveService, context) {
var object,
newParent,
currentParent;
if (context.selectedObject) {
newParent = context.domainObject;
object = context.selectedObject;
} else {
object = context.domainObject;
}
currentParent = object
.getCapability('context')
.getParent();
return {
perform: function () {
if (newParent) {
return moveService
.perform(object, newParent);
}
var dialogTitle,
label,
validateLocation;
dialogTitle = [
"Move ",
object.getModel().name,
" to a new location"
].join("");
label = "Move To";
validateLocation = function (newParent) {
return moveService
.validate(object, newParent);
};
return locationService.getLocationFromUser(
dialogTitle,
label,
validateLocation,
currentParent
).then(function (newParent) {
return moveService
.perform(object, newParent);
});
}
};
}
return MoveAction;
}
);

View File

@ -0,0 +1,106 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* CopyService provides an interface for deep copying objects from one
* location to another. It also provides a method for determining if
* an object can be copied to a specific location.
*/
function CopyService($q, creationService, policyService) {
/**
* duplicateObject duplicates a `domainObject` into the composition
* of `parent`, and then duplicates the composition of
* `domainObject` into the new object.
*
* This function is a recursive deep copy.
*
* @param {DomainObject} domainObject - the domain object to
* duplicate.
* @param {DomainObject} parent - the parent domain object to
* create the duplicate in.
* @returns {Promise} A promise that is fulfilled when the
* duplicate operation has completed.
*/
function duplicateObject(domainObject, parent) {
var model = JSON.parse(JSON.stringify(domainObject.getModel()));
if (domainObject.hasCapability('composition')) {
model.composition = [];
}
return creationService
.createObject(model, parent)
.then(function (newObject) {
if (!domainObject.hasCapability('composition')) {
return;
}
return domainObject
.useCapability('composition')
.then(function (composees) {
// Duplicate composition serially to prevent
// write conflicts.
return composees.reduce(function (promise, composee) {
return promise.then(function () {
return duplicateObject(composee, newObject);
});
}, $q.when(undefined));
});
});
}
return {
/**
* Returns true if `object` can be copied into
* `parentCandidate`'s composition.
*/
validate: function (object, parentCandidate) {
if (!parentCandidate || !parentCandidate.getId) {
return false;
}
if (parentCandidate.getId() === object.getId()) {
return false;
}
return policyService.allow(
"composition",
parentCandidate.getCapability('type'),
object.getCapability('type')
);
},
/**
* Wrapper, @see {@link duplicateObject} for implementation.
*/
perform: function (object, parentObject) {
return duplicateObject(object, parentObject);
}
};
}
return CopyService;
}
);

View File

@ -0,0 +1,76 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* LinkService provides an interface for linking objects to additional
* locations. It also provides a method for determining if an object
* can be copied to a specific location.
*/
function LinkService(policyService) {
return {
/**
* Returns `true` if `object` can be linked into
* `parentCandidate`'s composition.
*/
validate: function (object, parentCandidate) {
if (!parentCandidate || !parentCandidate.getId) {
return false;
}
if (parentCandidate.getId() === object.getId()) {
return false;
}
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
return false;
}
return policyService.allow(
"composition",
parentCandidate.getCapability('type'),
object.getCapability('type')
);
},
/**
* Link `object` into `parentObject`'s composition.
*
* @returns {Promise} A promise that is fulfilled when the
* linking operation has completed.
*/
perform: function (object, parentObject) {
return parentObject.useCapability('mutation', function (model) {
if (model.composition.indexOf(object.getId()) === -1) {
model.composition.push(object.getId());
}
}).then(function () {
return parentObject.getCapability('persistence').persist();
});
}
};
}
return LinkService;
}
);

View File

@ -0,0 +1,83 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* The LocationService allows for easily prompting the user for a
* location in the root tree.
*/
function LocationService(dialogService) {
return {
/** Prompt the user to select a location. Returns a promise
* that is resolved with a domainObject representing the
* location selected by the user.
*
* @param {string} title - title of location dialog
* @param {string} label - label for location input field
* @param {function} validate - function that validates
* selections.
* @param {domainObject} initialLocation - tree location to
* display at start
* @returns {Promise} promise for a domain object.
*/
getLocationFromUser: function (title, label, validate, initialLocation) {
var formStructure,
formState;
formStructure = {
sections: [
{
name: 'Location',
rows: [
{
name: label,
control: "locator",
validate: validate,
key: 'location'
}
]
}
],
name: title
};
formState = {
location: initialLocation
};
return dialogService
.getUserInput(formStructure, formState)
.then(function (formState) {
return formState.location;
});
}
};
}
return LocationService;
}
);

View File

@ -0,0 +1,83 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* MoveService provides an interface for moving objects from one
* location to another. It also provides a method for determining if
* an object can be copied to a specific location.
*/
function MoveService(policyService, linkService) {
return {
/**
* Returns `true` if `object` can be moved into
* `parentCandidate`'s composition.
*/
validate: function (object, parentCandidate) {
var currentParent = object
.getCapability('context')
.getParent();
if (!parentCandidate || !parentCandidate.getId) {
return false;
}
if (parentCandidate.getId() === currentParent.getId()) {
return false;
}
if (parentCandidate.getId() === object.getId()) {
return false;
}
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
return false;
}
return policyService.allow(
"composition",
parentCandidate.getCapability('type'),
object.getCapability('type')
);
},
/**
* Move `object` into `parentObject`'s composition.
*
* @returns {Promise} A promise that is fulfilled when the
* move operation has completed.
*/
perform: function (object, parentObject) {
return linkService
.perform(object, parentObject)
.then(function () {
return object
.getCapability('action')
.perform('remove');
});
}
};
}
return MoveService;
}
);

View File

@ -0,0 +1,158 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define, jasmine, */
define(
function () {
"use strict";
/**
* @typedef DomainObjectConfig
* @type {object}
* @property {string} [name] a name for the underlying jasmine spy
* object mockDomainObject. Used as
* @property {string} [id] initial id value for the domainOBject.
* @property {object} [model] initial values for the object's model.
* @property {object} [capabilities] an object containing
* capability definitions.
*/
var configObjectProps = ['model', 'capabilities'];
/**
* Internal function for ensuring an object is an instance of a
* DomainObjectConfig.
*/
function ensureValidConfigObject(config) {
if (!config || !config.hasOwnProperty) {
config = {};
}
if (!config.name) {
config.name = 'domainObject';
}
configObjectProps.forEach(function (prop) {
if (!config[prop] || !config[prop].hasOwnProperty) {
config[prop] = {};
}
});
return config;
}
/**
* Defines a factory function which takes a `config` object and returns
* a mock domainObject. The config object is an easy way to provide
* initial properties for the domainObject-- they can be changed at any
* time by directly modifying the domainObject's properties.
*
* @param {Object} [config] initial configuration for a domain object.
* @returns {Object} mockDomainObject
*/
function domainObjectFactory(config) {
config = ensureValidConfigObject(config);
var domainObject = jasmine.createSpyObj(config.name, [
'getId',
'getModel',
'getCapability',
'hasCapability',
'useCapability'
]);
domainObject.model = JSON.parse(JSON.stringify(config.model));
domainObject.capabilities = config.capabilities;
domainObject.id = config.id;
/**
* getId: Returns `domainObject.id`.
*
* @returns {string} id
*/
domainObject.getId.andCallFake(function () {
return domainObject.id;
});
/**
* getModel: Returns `domainObject.model`.
*
* @returns {object} model
*/
domainObject.getModel.andCallFake(function () {
return domainObject.model;
});
/**
* getCapability: returns a `capability` object defined in
* domainObject.capabilities. Returns undefined if capability
* does not exist.
*
* @param {string} capability name of the capability to return.
* @returns {*} capability object
*/
domainObject.getCapability.andCallFake(function (capability) {
if (config.capabilities.hasOwnProperty(capability)) {
return config.capabilities[capability];
}
});
/**
* hasCapability: return true if domainObject.capabilities has a
* property named `capability`, otherwise returns false.
*
* @param {string} capability name of the capability to test for
* existence of.
* @returns {boolean}
*/
domainObject.hasCapability.andCallFake(function (capability) {
return config.capabilities.hasOwnProperty(capability);
});
/**
* useCapability: find a capability in domainObject.capabilities
* and call that capabilities' invoke method. If the capability
* does not have an invoke method, will throw an error.
*
* @param {string} capability name of a capability to invoke.
* @param {...*} params to pass to the capability's `invoke` method.
* @returns {*} result whatever was returned by `invoke`.
*/
domainObject.useCapability.andCallFake(function (capability) {
if (config.capabilities.hasOwnProperty(capability)) {
if (!config.capabilities[capability].invoke) {
throw new Error(
capability + ' missing invoke function.'
);
}
var passThroughArgs = [].slice.call(arguments, 1);
return config
.capabilities[capability]
.invoke
.apply(null, passThroughArgs);
}
});
return domainObject;
}
return domainObjectFactory;
}
);

View File

@ -0,0 +1,174 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect */
define(
[
'../../src/actions/CopyAction',
'../services/MockCopyService',
'../DomainObjectFactory'
],
function (CopyAction, MockCopyService, domainObjectFactory) {
"use strict";
describe("Copy Action", function () {
var copyAction,
locationService,
locationServicePromise,
copyService,
context,
selectedObject,
selectedObjectContextCapability,
currentParent,
newParent;
beforeEach(function () {
selectedObjectContextCapability = jasmine.createSpyObj(
'selectedObjectContextCapability',
[
'getParent'
]
);
selectedObject = domainObjectFactory({
name: 'selectedObject',
model: {
name: 'selectedObject'
},
capabilities: {
context: selectedObjectContextCapability
}
});
currentParent = domainObjectFactory({
name: 'currentParent'
});
selectedObjectContextCapability
.getParent
.andReturn(currentParent);
newParent = domainObjectFactory({
name: 'newParent'
});
locationService = jasmine.createSpyObj(
'locationService',
[
'getLocationFromUser'
]
);
locationServicePromise = jasmine.createSpyObj(
'locationServicePromise',
[
'then'
]
);
locationService
.getLocationFromUser
.andReturn(locationServicePromise);
copyService = new MockCopyService();
});
describe("with context from context-action", function () {
beforeEach(function () {
context = {
domainObject: selectedObject
};
copyAction = new CopyAction(
locationService,
copyService,
context
);
});
it("initializes happily", function () {
expect(copyAction).toBeDefined();
});
describe("when performed it", function () {
beforeEach(function () {
copyAction.perform();
});
it("prompts for location", function () {
expect(locationService.getLocationFromUser)
.toHaveBeenCalledWith(
"Duplicate selectedObject to a location",
"Duplicate To",
jasmine.any(Function),
currentParent
);
});
it("waits for location from user", function () {
expect(locationServicePromise.then)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("copys object to selected location", function () {
locationServicePromise
.then
.mostRecentCall
.args[0](newParent);
expect(copyService.perform)
.toHaveBeenCalledWith(selectedObject, newParent);
});
});
});
describe("with context from drag-drop", function () {
beforeEach(function () {
context = {
selectedObject: selectedObject,
domainObject: newParent
};
copyAction = new CopyAction(
locationService,
copyService,
context
);
});
it("initializes happily", function () {
expect(copyAction).toBeDefined();
});
it("performs copy immediately", function () {
copyAction.perform();
expect(copyService.perform)
.toHaveBeenCalledWith(selectedObject, newParent);
});
});
});
}
);

View File

@ -0,0 +1,174 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect */
define(
[
'../../src/actions/LinkAction',
'../services/MockLinkService',
'../DomainObjectFactory'
],
function (LinkAction, MockLinkService, domainObjectFactory) {
"use strict";
describe("Link Action", function () {
var linkAction,
locationService,
locationServicePromise,
linkService,
context,
selectedObject,
selectedObjectContextCapability,
currentParent,
newParent;
beforeEach(function () {
selectedObjectContextCapability = jasmine.createSpyObj(
'selectedObjectContextCapability',
[
'getParent'
]
);
selectedObject = domainObjectFactory({
name: 'selectedObject',
model: {
name: 'selectedObject'
},
capabilities: {
context: selectedObjectContextCapability
}
});
currentParent = domainObjectFactory({
name: 'currentParent'
});
selectedObjectContextCapability
.getParent
.andReturn(currentParent);
newParent = domainObjectFactory({
name: 'newParent'
});
locationService = jasmine.createSpyObj(
'locationService',
[
'getLocationFromUser'
]
);
locationServicePromise = jasmine.createSpyObj(
'locationServicePromise',
[
'then'
]
);
locationService
.getLocationFromUser
.andReturn(locationServicePromise);
linkService = new MockLinkService();
});
describe("with context from context-action", function () {
beforeEach(function () {
context = {
domainObject: selectedObject
};
linkAction = new LinkAction(
locationService,
linkService,
context
);
});
it("initializes happily", function () {
expect(linkAction).toBeDefined();
});
describe("when performed it", function () {
beforeEach(function () {
linkAction.perform();
});
it("prompts for location", function () {
expect(locationService.getLocationFromUser)
.toHaveBeenCalledWith(
"Link selectedObject to a new location",
"Link To",
jasmine.any(Function),
currentParent
);
});
it("waits for location from user", function () {
expect(locationServicePromise.then)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("links object to selected location", function () {
locationServicePromise
.then
.mostRecentCall
.args[0](newParent);
expect(linkService.perform)
.toHaveBeenCalledWith(selectedObject, newParent);
});
});
});
describe("with context from drag-drop", function () {
beforeEach(function () {
context = {
selectedObject: selectedObject,
domainObject: newParent
};
linkAction = new LinkAction(
locationService,
linkService,
context
);
});
it("initializes happily", function () {
expect(linkAction).toBeDefined();
});
it("performs link immediately", function () {
linkAction.perform();
expect(linkService.perform)
.toHaveBeenCalledWith(selectedObject, newParent);
});
});
});
}
);

View File

@ -0,0 +1,174 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect */
define(
[
'../../src/actions/MoveAction',
'../services/MockMoveService',
'../DomainObjectFactory'
],
function (MoveAction, MockMoveService, domainObjectFactory) {
"use strict";
describe("Move Action", function () {
var moveAction,
locationService,
locationServicePromise,
moveService,
context,
selectedObject,
selectedObjectContextCapability,
currentParent,
newParent;
beforeEach(function () {
selectedObjectContextCapability = jasmine.createSpyObj(
'selectedObjectContextCapability',
[
'getParent'
]
);
selectedObject = domainObjectFactory({
name: 'selectedObject',
model: {
name: 'selectedObject'
},
capabilities: {
context: selectedObjectContextCapability
}
});
currentParent = domainObjectFactory({
name: 'currentParent'
});
selectedObjectContextCapability
.getParent
.andReturn(currentParent);
newParent = domainObjectFactory({
name: 'newParent'
});
locationService = jasmine.createSpyObj(
'locationService',
[
'getLocationFromUser'
]
);
locationServicePromise = jasmine.createSpyObj(
'locationServicePromise',
[
'then'
]
);
locationService
.getLocationFromUser
.andReturn(locationServicePromise);
moveService = new MockMoveService();
});
describe("with context from context-action", function () {
beforeEach(function () {
context = {
domainObject: selectedObject
};
moveAction = new MoveAction(
locationService,
moveService,
context
);
});
it("initializes happily", function () {
expect(moveAction).toBeDefined();
});
describe("when performed it", function () {
beforeEach(function () {
moveAction.perform();
});
it("prompts for location", function () {
expect(locationService.getLocationFromUser)
.toHaveBeenCalledWith(
"Move selectedObject to a new location",
"Move To",
jasmine.any(Function),
currentParent
);
});
it("waits for location from user", function () {
expect(locationServicePromise.then)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("moves object to selected location", function () {
locationServicePromise
.then
.mostRecentCall
.args[0](newParent);
expect(moveService.perform)
.toHaveBeenCalledWith(selectedObject, newParent);
});
});
});
describe("with context from drag-drop", function () {
beforeEach(function () {
context = {
selectedObject: selectedObject,
domainObject: newParent
};
moveAction = new MoveAction(
locationService,
moveService,
context
);
});
it("initializes happily", function () {
expect(moveAction).toBeDefined();
});
it("performs move immediately", function () {
moveAction.perform();
expect(moveService.perform)
.toHaveBeenCalledWith(selectedObject, newParent);
});
});
});
}
);

View File

@ -0,0 +1,272 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
define(
[
'../../src/services/CopyService',
'../DomainObjectFactory'
],
function (CopyService, domainObjectFactory) {
"use strict";
function synchronousPromise(value) {
var promise = {
then: function (callback) {
return synchronousPromise(callback(value));
}
};
spyOn(promise, 'then').andCallThrough();
return promise;
}
describe("CopyService", function () {
describe("validate", function () {
var policyService,
copyService,
object,
parentCandidate,
validate;
beforeEach(function () {
policyService = jasmine.createSpyObj(
'policyService',
['allow']
);
copyService = new CopyService(
null,
null,
policyService
);
object = domainObjectFactory({
name: 'object',
capabilities: {
type: { type: 'object' }
}
});
parentCandidate = domainObjectFactory({
name: 'parentCandidate',
capabilities: {
type: { type: 'parentCandidate' }
}
});
validate = function () {
return copyService.validate(object, parentCandidate);
};
});
it("does not allow invalid parentCandidate", function () {
parentCandidate = undefined;
expect(validate()).toBe(false);
parentCandidate = {};
expect(validate()).toBe(false);
});
it("does not allow copying into source object", function () {
object.id = parentCandidate.id = 'abc';
expect(validate()).toBe(false);
});
describe("defers to policyService", function () {
beforeEach(function () {
object.id = 'a';
parentCandidate.id = 'b';
});
it("calls policy service with correct args", function () {
validate();
expect(policyService.allow).toHaveBeenCalledWith(
"composition",
parentCandidate.capabilities.type,
object.capabilities.type
);
});
it("and returns false", function () {
policyService.allow.andReturn(false);
expect(validate()).toBe(false);
});
it("and returns true", function () {
policyService.allow.andReturn(true);
expect(validate()).toBe(true);
});
});
});
describe("perform", function () {
var mockQ,
creationService,
createObjectPromise,
copyService,
object,
newParent,
copyResult,
copyFinished;
describe("on domain object without composition", function () {
beforeEach(function () {
object = domainObjectFactory({
name: 'object',
id: 'abc',
model: {
name: 'some object'
}
});
newParent = domainObjectFactory({
name: 'newParent',
id: '456',
model: {
composition: []
}
});
creationService = jasmine.createSpyObj(
'creationService',
['createObject']
);
createObjectPromise = synchronousPromise(undefined);
creationService.createObject.andReturn(createObjectPromise);
copyService = new CopyService(null, creationService);
copyResult = copyService.perform(object, newParent);
copyFinished = jasmine.createSpy('copyFinished');
copyResult.then(copyFinished);
});
it("uses creation service", function () {
expect(creationService.createObject)
.toHaveBeenCalledWith(jasmine.any(Object), newParent);
expect(createObjectPromise.then)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("deep clones object model", function () {
var newModel = creationService
.createObject
.mostRecentCall
.args[0];
expect(newModel).toEqual(object.model);
expect(newModel).not.toBe(object.model);
});
it("returns a promise", function () {
expect(copyResult).toBeDefined();
expect(copyFinished).toHaveBeenCalled();
});
});
describe("on domainObject with composition", function () {
var childObject,
compositionCapability,
compositionPromise;
beforeEach(function () {
mockQ = jasmine.createSpyObj('mockQ', ['when']);
mockQ.when.andCallFake(synchronousPromise);
childObject = domainObjectFactory({
name: 'childObject',
id: 'def',
model: {
name: 'a child object'
}
});
compositionCapability = jasmine.createSpyObj(
'compositionCapability',
['invoke']
);
compositionPromise = jasmine.createSpyObj(
'compositionPromise',
['then']
);
compositionCapability
.invoke
.andReturn(compositionPromise);
object = domainObjectFactory({
name: 'object',
id: 'abc',
model: {
name: 'some object',
composition: ['def']
},
capabilities: {
composition: compositionCapability
}
});
newParent = domainObjectFactory({
name: 'newParent',
id: '456',
model: {
composition: []
}
});
creationService = jasmine.createSpyObj(
'creationService',
['createObject']
);
createObjectPromise = synchronousPromise(undefined);
creationService.createObject.andReturn(createObjectPromise);
copyService = new CopyService(mockQ, creationService);
copyResult = copyService.perform(object, newParent);
copyFinished = jasmine.createSpy('copyFinished');
copyResult.then(copyFinished);
});
it("uses creation service", function () {
expect(creationService.createObject)
.toHaveBeenCalledWith(jasmine.any(Object), newParent);
expect(createObjectPromise.then)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("clears model composition", function () {
var newModel = creationService
.createObject
.mostRecentCall
.args[0];
expect(newModel.composition.length).toBe(0);
expect(newModel.name).toBe('some object');
});
it("recursively clones it's children", function () {
expect(creationService.createObject.calls.length).toBe(1);
expect(compositionCapability.invoke).toHaveBeenCalled();
compositionPromise.then.mostRecentCall.args[0]([childObject]);
expect(creationService.createObject.calls.length).toBe(2);
});
it("returns a promise", function () {
expect(copyResult.then).toBeDefined();
expect(copyFinished).toHaveBeenCalled();
});
});
});
});
}
);

View File

@ -0,0 +1,183 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect */
define(
[
'../../src/services/LinkService',
'../DomainObjectFactory'
],
function (LinkService, domainObjectFactory) {
"use strict";
describe("LinkService", function () {
var linkService,
mockPolicyService;
beforeEach(function () {
mockPolicyService = jasmine.createSpyObj(
'policyService',
['allow']
);
linkService = new LinkService(mockPolicyService);
});
describe("validate", function () {
var object,
parentCandidate,
validate;
beforeEach(function () {
object = domainObjectFactory({
name: 'object'
});
parentCandidate = domainObjectFactory({
name: 'parentCandidate'
});
validate = function () {
return linkService.validate(object, parentCandidate);
};
});
it("does not allow invalid parentCandidate", function () {
parentCandidate = undefined;
expect(validate()).toBe(false);
parentCandidate = {};
expect(validate()).toBe(false);
});
it("does not allow parent to be object", function () {
parentCandidate.id = object.id = 'abc';
expect(validate()).toBe(false);
});
it("does not allow parent that contains object", function () {
object.id = 'abc';
parentCandidate.id = 'xyz';
parentCandidate.model.composition = ['abc'];
expect(validate()).toBe(false);
});
describe("defers to policyService", function () {
beforeEach(function () {
object.id = 'abc';
object.capabilities.type = { type: 'object' };
parentCandidate.id = 'xyz';
parentCandidate.capabilities.type = {
type: 'parentCandidate'
};
parentCandidate.model.composition = [];
});
it("calls policy service with correct args", function () {
validate();
expect(mockPolicyService.allow).toHaveBeenCalledWith(
"composition",
parentCandidate.capabilities.type,
object.capabilities.type
);
});
it("and returns false", function () {
mockPolicyService.allow.andReturn(true);
expect(validate()).toBe(true);
expect(mockPolicyService.allow).toHaveBeenCalled();
});
it("and returns true", function () {
mockPolicyService.allow.andReturn(false);
expect(validate()).toBe(false);
expect(mockPolicyService.allow).toHaveBeenCalled();
});
});
});
describe("perform", function () {
var object,
parentModel,
parentObject,
mutationPromise,
persistenceCapability;
beforeEach(function () {
mutationPromise = jasmine.createSpyObj(
'promise',
['then']
);
persistenceCapability = jasmine.createSpyObj(
'persistenceCapability',
['persist']
);
parentModel = {
composition: []
};
parentObject = domainObjectFactory({
name: 'parentObject',
model: parentModel,
capabilities: {
mutation: {
invoke: function (mutator) {
mutator(parentModel);
return mutationPromise;
}
},
persistence: persistenceCapability
}
});
object = domainObjectFactory({
name: 'object',
id: 'xyz'
});
parentObject.getCapability.andReturn(persistenceCapability);
});
it("modifies parent model composition", function () {
expect(parentModel.composition.length).toBe(0);
linkService.perform(object, parentObject);
expect(parentObject.useCapability).toHaveBeenCalledWith(
'mutation',
jasmine.any(Function)
);
expect(parentModel.composition).toContain('xyz');
});
it("persists parent", function () {
linkService.perform(object, parentObject);
expect(mutationPromise.then).toHaveBeenCalled();
mutationPromise.then.calls[0].args[0]();
expect(parentObject.getCapability)
.toHaveBeenCalledWith('persistence');
expect(persistenceCapability.persist).toHaveBeenCalled();
});
});
});
}
);

View File

@ -0,0 +1,151 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect */
define(
[
'../../src/services/LocationService'
],
function (LocationService) {
"use strict";
describe("LocationService", function () {
var dialogService,
locationService,
dialogServicePromise,
chainedPromise;
beforeEach(function () {
dialogService = jasmine.createSpyObj(
'dialogService',
['getUserInput']
);
dialogServicePromise = jasmine.createSpyObj(
'dialogServicePromise',
['then']
);
chainedPromise = jasmine.createSpyObj(
'chainedPromise',
['then']
);
dialogServicePromise.then.andReturn(chainedPromise);
dialogService.getUserInput.andReturn(dialogServicePromise);
locationService = new LocationService(dialogService);
});
describe("getLocationFromUser", function () {
var title,
label,
validate,
initialLocation,
locationResult,
formStructure,
formState;
beforeEach(function () {
title = "Get a location to do something";
label = "a location";
validate = function () { return true; };
initialLocation = { key: "a key" };
locationResult = locationService.getLocationFromUser(
title,
label,
validate,
initialLocation
);
formStructure = dialogService
.getUserInput
.mostRecentCall
.args[0];
formState = dialogService
.getUserInput
.mostRecentCall
.args[1];
});
it("calls through to dialogService", function () {
expect(dialogService.getUserInput).toHaveBeenCalledWith(
jasmine.any(Object),
jasmine.any(Object)
);
expect(formStructure.name).toBe(title);
});
it("returns a promise", function () {
expect(locationResult.then).toBeDefined();
});
describe("formStructure", function () {
var locationSection,
inputRow;
beforeEach(function () {
locationSection = formStructure.sections[0];
inputRow = locationSection.rows[0];
});
it("has a location section", function () {
expect(locationSection).toBeDefined();
expect(locationSection.name).toBe('Location');
});
it("has a input row", function () {
expect(inputRow.control).toBe('locator');
expect(inputRow.key).toBe('location');
expect(inputRow.name).toBe(label);
expect(inputRow.validate).toBe(validate);
});
});
describe("formState", function () {
it("has an initial location", function () {
expect(formState.location).toBe(initialLocation);
});
});
describe("resolution of dialog service promise", function () {
var resolution,
resolver,
dialogResult,
selectedLocation;
beforeEach(function () {
resolver =
dialogServicePromise.then.mostRecentCall.args[0];
selectedLocation = { key: "i'm a location key" };
dialogResult = {
location: selectedLocation
};
resolution = resolver(dialogResult);
});
it("returns selectedLocation", function () {
expect(resolution).toBe(selectedLocation);
});
});
});
});
}
);

View File

@ -0,0 +1,99 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,jasmine */
define(
function () {
"use strict";
/**
* MockCopyService provides the same interface as the copyService,
* returning promises where it would normally do so. At it's core,
* it is a jasmine spy object, but it also tracks the promises it
* returns and provides shortcut methods for resolving those promises
* synchronously.
*
* Usage:
*
* ```javascript
* var copyService = new MockCopyService();
*
* // validate is a standard jasmine spy.
* copyService.validate.andReturn(true);
* var isValid = copyService.validate(object, parentCandidate);
* expect(isValid).toBe(true);
*
* // perform returns promises and tracks them.
* var whenCopied = jasmine.createSpy('whenCopied');
* copyService.perform(object, parentObject).then(whenCopied);
* expect(whenCopied).not.toHaveBeenCalled();
* copyService.perform.mostRecentCall.resolve('someArg');
* expect(whenCopied).toHaveBeenCalledWith('someArg');
* ```
*/
function MockCopyService() {
// track most recent call of a function,
// perform automatically returns
var mockCopyService = jasmine.createSpyObj(
'MockCopyService',
[
'validate',
'perform'
]
);
mockCopyService.perform.andCallFake(function () {
var performPromise,
callExtensions,
spy;
performPromise = jasmine.createSpyObj(
'performPromise',
['then']
);
callExtensions = {
promise: performPromise,
resolve: function (resolveWith) {
performPromise.then.calls.forEach(function (call) {
call.args[0](resolveWith);
});
}
};
spy = this.perform;
Object.keys(callExtensions).forEach(function (key) {
spy.mostRecentCall[key] = callExtensions[key];
spy.calls[spy.calls.length - 1][key] = callExtensions[key];
});
return performPromise;
});
return mockCopyService;
}
return MockCopyService;
}
);

View File

@ -0,0 +1,99 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,jasmine */
define(
function () {
"use strict";
/**
* MockLinkService provides the same interface as the linkService,
* returning promises where it would normally do so. At it's core,
* it is a jasmine spy object, but it also tracks the promises it
* returns and provides shortcut methods for resolving those promises
* synchronously.
*
* Usage:
*
* ```javascript
* var linkService = new MockLinkService();
*
* // validate is a standard jasmine spy.
* linkService.validate.andReturn(true);
* var isValid = linkService.validate(object, parentObject);
* expect(isValid).toBe(true);
*
* // perform returns promises and tracks them.
* var whenLinked = jasmine.createSpy('whenLinked');
* linkService.perform(object, parentObject).then(whenLinked);
* expect(whenLinked).not.toHaveBeenCalled();
* linkService.perform.mostRecentCall.resolve('someArg');
* expect(whenLinked).toHaveBeenCalledWith('someArg');
* ```
*/
function MockLinkService() {
// track most recent call of a function,
// perform automatically returns
var mockLinkService = jasmine.createSpyObj(
'MockLinkService',
[
'validate',
'perform'
]
);
mockLinkService.perform.andCallFake(function () {
var performPromise,
callExtensions,
spy;
performPromise = jasmine.createSpyObj(
'performPromise',
['then']
);
callExtensions = {
promise: performPromise,
resolve: function (resolveWith) {
performPromise.then.calls.forEach(function (call) {
call.args[0](resolveWith);
});
}
};
spy = this.perform;
Object.keys(callExtensions).forEach(function (key) {
spy.mostRecentCall[key] = callExtensions[key];
spy.calls[spy.calls.length - 1][key] = callExtensions[key];
});
return performPromise;
});
return mockLinkService;
}
return MockLinkService;
}
);

View File

@ -0,0 +1,99 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,jasmine */
define(
function () {
"use strict";
/**
* MockMoveService provides the same interface as the moveService,
* returning promises where it would normally do so. At it's core,
* it is a jasmine spy object, but it also tracks the promises it
* returns and provides shortcut methods for resolving those promises
* synchronously.
*
* Usage:
*
* ```javascript
* var moveService = new MockMoveService();
*
* // validate is a standard jasmine spy.
* moveService.validate.andReturn(true);
* var isValid = moveService.validate(object, parentCandidate);
* expect(isValid).toBe(true);
*
* // perform returns promises and tracks them.
* var whenCopied = jasmine.createSpy('whenCopied');
* moveService.perform(object, parentObject).then(whenCopied);
* expect(whenCopied).not.toHaveBeenCalled();
* moveService.perform.mostRecentCall.resolve('someArg');
* expect(whenCopied).toHaveBeenCalledWith('someArg');
* ```
*/
function MockMoveService() {
// track most recent call of a function,
// perform automatically returns
var mockMoveService = jasmine.createSpyObj(
'MockMoveService',
[
'validate',
'perform'
]
);
mockMoveService.perform.andCallFake(function () {
var performPromise,
callExtensions,
spy;
performPromise = jasmine.createSpyObj(
'performPromise',
['then']
);
callExtensions = {
promise: performPromise,
resolve: function (resolveWith) {
performPromise.then.calls.forEach(function (call) {
call.args[0](resolveWith);
});
}
};
spy = this.perform;
Object.keys(callExtensions).forEach(function (key) {
spy.mostRecentCall[key] = callExtensions[key];
spy.calls[spy.calls.length - 1][key] = callExtensions[key];
});
return performPromise;
});
return mockMoveService;
}
return MockMoveService;
}
);

View File

@ -0,0 +1,189 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect */
define(
[
'../../src/services/MoveService',
'../services/MockLinkService',
'../DomainObjectFactory'
],
function (MoveService, MockLinkService, domainObjectFactory) {
"use strict";
describe("MoveService", function () {
var moveService,
policyService,
linkService;
beforeEach(function () {
policyService = jasmine.createSpyObj(
'policyService',
['allow']
);
linkService = new MockLinkService();
moveService = new MoveService(policyService, linkService);
});
describe("validate", function () {
var object,
objectContextCapability,
currentParent,
parentCandidate,
validate;
beforeEach(function () {
objectContextCapability = jasmine.createSpyObj(
'objectContextCapability',
[
'getParent'
]
);
object = domainObjectFactory({
name: 'object',
id: 'a',
capabilities: {
context: objectContextCapability,
type: { type: 'object' }
}
});
currentParent = domainObjectFactory({
name: 'currentParent',
id: 'b'
});
objectContextCapability.getParent.andReturn(currentParent);
parentCandidate = domainObjectFactory({
name: 'parentCandidate',
model: { composition: [] },
id: 'c',
capabilities: {
type: { type: 'parentCandidate' }
}
});
validate = function () {
return moveService.validate(object, parentCandidate);
};
});
it("does not allow an invalid parent", function () {
parentCandidate = undefined;
expect(validate()).toBe(false);
parentCandidate = {};
expect(validate()).toBe(false);
});
it("does not allow moving to current parent", function () {
parentCandidate.id = currentParent.id = 'xyz';
expect(validate()).toBe(false);
});
it("does not allow moving to self", function () {
object.id = parentCandidate.id = 'xyz';
expect(validate()).toBe(false);
});
it("does not allow moving to the same location", function () {
object.id = 'abc';
parentCandidate.model.composition = ['abc'];
expect(validate()).toBe(false);
});
describe("defers to policyService", function () {
it("calls policy service with correct args", function () {
validate();
expect(policyService.allow).toHaveBeenCalledWith(
"composition",
parentCandidate.capabilities.type,
object.capabilities.type
);
});
it("and returns false", function () {
policyService.allow.andReturn(false);
expect(validate()).toBe(false);
});
it("and returns true", function () {
policyService.allow.andReturn(true);
expect(validate()).toBe(true);
});
});
});
describe("perform", function () {
var object,
parentObject,
actionCapability;
beforeEach(function () {
actionCapability = jasmine.createSpyObj(
'actionCapability',
['perform']
);
object = domainObjectFactory({
name: 'object',
capabilities: {
action: actionCapability
}
});
parentObject = domainObjectFactory({
name: 'parentObject'
});
moveService.perform(object, parentObject);
});
it("links object to parentObject", function () {
expect(linkService.perform).toHaveBeenCalledWith(
object,
parentObject
);
});
it("waits for result of link", function () {
expect(linkService.perform.mostRecentCall.promise.then)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("removes object when link is completed", function () {
linkService.perform.mostRecentCall.resolve();
expect(object.getCapability)
.toHaveBeenCalledWith('action');
expect(actionCapability.perform)
.toHaveBeenCalledWith('remove');
});
});
});
}
);

View File

@ -0,0 +1,9 @@
[
"actions/CopyAction",
"actions/LinkAction",
"actions/MoveAction",
"services/CopyService",
"services/LinkService",
"services/MoveService",
"services/LocationService"
]

View File

@ -34,50 +34,62 @@
<!-- Drag handles -->
<span ng-show="domainObject.hasCapability('editor')">
<span style="position: absolute; left: 12px; right: 12px; top: 12px; bottom: 12px; cursor: move;"
<span
class="edit-handle edit-move"
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [0,0])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
<span style="position: absolute; left: 0px; width: 12px; top: 12px; bottom: 12px; cursor: w-resize;"
<!--
<span
class="edit-handle edit-resize-w"
mct-drag-down="controller.startDrag(childObject.getId(), [1,0], [-1,0])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
<span style="position: absolute; right: 0px; width: 12px; top: 12px; bottom: 12px; cursor: e-resize;"
<span
class="edit-handle edit-resize-e"
mct-drag-down="controller.startDrag(childObject.getId(), [0,0], [1,0])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
<span style="position: absolute; left: 12px; right: 12px; top: 0px; height: 12px; cursor: n-resize;"
<span
class="edit-handle edit-resize-n"
mct-drag-down="controller.startDrag(childObject.getId(), [0,1], [0,-1])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
<span style="position: absolute; left: 12px; right: 12px; bottom: 0px; height: 12px; cursor: s-resize;"
<span
class="edit-handle edit-resize-s"
mct-drag-down="controller.startDrag(childObject.getId(), [0,0], [0,1])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
-->
<span style="position: absolute; left: 0px; width: 12px; top: 0px; height: 12px; cursor: nw-resize;"
<span
class="edit-corner edit-resize-nw"
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [-1,-1])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
<span style="position: absolute; right: 0px; width: 12px; top: 0px; height: 12px; cursor: ne-resize;"
<!--span
class="edit-corner edit-resize-nw"
style="position: absolute; right: 0px; width: 12px; top: 0px; height: 12px; cursor: ne-resize;"
mct-drag-down="controller.startDrag(childObject.getId(), [0,1], [1,-1])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
<span style="position: absolute; left: 0px; width: 12px; bottom: 0px; height: 12px; cursor: sw-resize;"
</span-->
<span
class="edit-corner edit-resize-sw"
mct-drag-down="controller.startDrag(childObject.getId(), [1,0], [-1,1])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">
</span>
<span style="position: absolute; right: 0px; width: 12px; bottom: 0px; height: 12px; cursor: se-resize;"
<span
class="edit-corner edit-resize-se"
mct-drag-down="controller.startDrag(childObject.getId(), [0,0], [1,1])"
mct-drag="controller.continueDrag(delta)"
mct-drag-up="controller.endDrag()">

View File

@ -8,6 +8,7 @@
"glyph": "6",
"templateUrl": "templates/plot.html",
"needs": [ "telemetry" ],
"priority": "preferred",
"delegation": true
}
],

View File

@ -22,16 +22,16 @@
<span ng-controller="PlotController as plot"
ng-mouseleave="representation.showControls = false">
<div class="gl-plot"
<div class="gl-plot"
ng-style="{ height: 100 / plot.getSubPlots().length + '%'}"
ng-repeat="subplot in plot.getSubPlots()">
<div class="gl-plot-legend">
<!-- ng-class is temporarily hard-coded in next element -->
<!-- ng-class is temporarily hard-coded in next element -->
<span
class='plot-legend-item'
class='plot-legend-item'
ng-repeat="telemetryObject in subplot.getTelemetryObjects()"
ng-class="plot.getLegendClass(telemetryObject)"
>
>
<span class='plot-color-swatch'
ng-style="{ 'background-color': plot.getColor($index) }">
</span>
@ -40,9 +40,9 @@
</div>
<div
class="gl-plot-coords"
ng-if="subplot.isHovering() && subplot.getHoverCoordinates()"
>
class="gl-plot-coords"
ng-if="subplot.isHovering() && subplot.getHoverCoordinates()"
>
{{subplot.getHoverCoordinates()}}
</div>
@ -75,8 +75,8 @@
ng-mouseenter="subplot.isHovering(true); representation.showControls = true;"
ng-mouseleave="subplot.isHovering(false)">
<!-- Out-of-bounds data indicators -->
<!-- ng-show is temporarily hard-coded in next element -->
<!-- Out-of-bounds data indicators -->
<!-- ng-show is temporarily hard-coded in next element -->
<div ng-show="1" class="l-oob-data l-oob-data-up"></div>
<div ng-show="1" class="l-oob-data l-oob-data-dwn"></div>
@ -98,7 +98,7 @@
</mct-chart>
<!-- TODO: Move into correct position; make part of group; infer from set of actions -->
<div class="gl-plot-local-controls"
<div class="l-local-controls gl-plot-local-controls"
ng-if="$first"
ng-show="representation.showControls"
style="position: absolute; top: 8px; right: 8px;">
@ -119,7 +119,7 @@
<span class="ui-symbol icon">I</span>
</a>
<div class="menu-element btn icon-btn very-subtle btn-menu dropdown click-invoke"
<div class="menu-element btn s-very-subtle btn-menu dropdown menus-to-left"
ng-if="plot.getModeOptions().length > 1"
ng-controller="ClickAwayController as toggle">
@ -127,7 +127,7 @@
<span class="ui-symbol icon type-icon">{{plot.getMode().glyph}}</span>
<span>{{plot.getMode().name}}</span>
<span class='ui-symbol icon invoke-menu'>v</span>
<span class='ui-symbol invoke-menu'>v</span>
<div class="menu dropdown" ng-show="toggle.isActive()">
<ul>

View File

@ -30,7 +30,7 @@
<span class="title-label" ng-if="structure.text">
{{structure.text}}
</span>
<span class='ui-symbol icon invoke-menu' ng-if="!structure.text">v</span>
<span class='ui-symbol invoke-menu' ng-if="!structure.text">v</span>
<div

View File

@ -38,7 +38,7 @@
placeholder="YYYY-DDD"
ng-pattern="/\d\d\d\d-\d\d\d/"
ng-model='datetime.date'
ng-required='true'/>
ng-required='ngRequired || partiallyComplete'/>
</span>
<span class='field control time sm'>
<input type='text'
@ -49,7 +49,7 @@
integer
ng-pattern='/\d+/'
ng-model="datetime.hour"
ng-required='true'/>
ng-required='ngRequired || partiallyComplete'/>
</span>
<span class='field control time sm'>
<input type='text'
@ -60,7 +60,7 @@
integer
ng-pattern='/\d+/'
ng-model="datetime.min"
ng-required='true'/>
ng-required='ngRequired || partiallyComplete'/>
</span>
<span class='field control time sm'>
<input type='text'
@ -71,7 +71,7 @@
integer
ng-pattern='/\d+/'
ng-model="datetime.sec"
ng-required='true'/>
ng-required='ngRequired || partiallyComplete'/>
</span>
<span class='field control timezone'>
UTC

View File

@ -28,7 +28,7 @@
<span class="title-label" ng-if="structure.text">
{{structure.text}}
</span>
<span class='ui-symbol icon invoke-menu'
<span class='ui-symbol invoke-menu'
ng-if="!structure.text">
v
</span>

View File

@ -52,15 +52,51 @@ define(
if (fullDateTime.isValid()) {
$scope.ngModel[$scope.field] = fullDateTime.valueOf();
}
// If anything is complete, say so in scope; there are
// ng-required usages that will update off of this (to
// allow datetime to be optional while still permitting
// incomplete input)
$scope.partiallyComplete =
Object.keys($scope.datetime).some(function (key) {
return $scope.datetime[key];
});
// Treat empty input as an undefined value
if (!$scope.partiallyComplete) {
$scope.ngModel[$scope.field] = undefined;
}
}
function updateDateTime(value) {
var m;
if (value !== undefined) {
m = moment.utc(value);
$scope.datetime = {
date: m.format(DATE_FORMAT),
hour: m.format("H"),
min: m.format("m"),
sec: m.format("s")
};
} else {
$scope.datetime = {};
}
}
// ...and update form values when actual field in model changes
$scope.$watch("ngModel[field]", updateDateTime);
// Update value whenever any field changes.
$scope.$watch("datetime.date", update);
$scope.$watch("datetime.hour", update);
$scope.$watch("datetime.min", update);
$scope.$watch("datetime.sec", update);
$scope.datetime = {};
// Initialize forms values
updateDateTime(
($scope.ngModel && $scope.field) ?
$scope.ngModel[$scope.field] : undefined
);
}
return DateTimeController;

View File

@ -57,6 +57,49 @@ define(
expect(mockScope.ngModel.test).toEqual(1417215313000);
});
it("reports when form input is partially complete", function () {
// This is needed to flag the control's state as invalid
// when it is partially complete without having it treated
// as required.
mockScope.ngModel = {};
mockScope.field = "test";
mockScope.datetime.date = "2014-332";
mockScope.datetime.hour = 22;
mockScope.datetime.min = 55;
// mockScope.datetime.sec = 13;
mockScope.$watch.mostRecentCall.args[1]();
expect(mockScope.partiallyComplete).toBeTruthy();
});
it("reports 'undefined' for empty input", function () {
mockScope.ngModel = { test: 12345 };
mockScope.field = "test";
mockScope.$watch.mostRecentCall.args[1]();
// Clear all inputs
mockScope.datetime = {};
mockScope.$watch.mostRecentCall.args[1]();
// Should have cleared out the time stamp
expect(mockScope.ngModel.test).toBeUndefined();
});
it("initializes form fields with values from ng-model", function () {
mockScope.ngModel = { test: 1417215313000 };
mockScope.field = "test";
mockScope.$watch.calls.forEach(function (call) {
if (call.args[0] === 'ngModel[field]') {
call.args[1](mockScope.ngModel.test);
}
});
expect(mockScope.datetime).toEqual({
date: "2014-332",
hour: "22",
min: "55",
sec: "13"
});
});
});
}
);
);

View File

@ -17,15 +17,18 @@
},
{
"key": "ELASTIC_ROOT",
"value": "/elastic"
"value": "/elastic",
"priority": "fallback"
},
{
"key": "ELASTIC_PATH",
"value": "mct/domain_object"
"value": "mct/domain_object",
"priority": "fallback"
},
{
"key": "ELASTIC_INDICATOR_INTERVAL",
"value": 15000
"value": 15000,
"priority": "fallback"
}
],
"indicators": [

View File

@ -43,7 +43,7 @@ define(
function DropGesture(dndService, $q, element, domainObject) {
var actionCapability = domainObject.getCapability('action'),
action; // Action for the drop, when it occurs
function broadcastDrop(id, event) {
// Find the relevant scope...
var scope = element && element.scope && element.scope(),
@ -92,17 +92,24 @@ define(
function drop(e) {
var event = (e || {}).originalEvent || e,
id = event.dataTransfer.getData(GestureConstants.MCT_DRAG_TYPE);
// Handle the drop; add the dropped identifier to the
// destination domain object's composition, and persist
// the change.
if (id) {
$q.when(action && action.perform()).then(function (result) {
broadcastDrop(id, event);
});
id = event.dataTransfer.getData(GestureConstants.MCT_DRAG_TYPE),
domainObjectType = domainObject.getModel().type;
// If currently in edit mode allow drag and drop gestures to the
// domain object. An exception to this is folders which have drop
// gestures in browse mode.
if (domainObjectType === 'folder' || domainObject.hasCapability('editor')) {
// Handle the drop; add the dropped identifier to the
// destination domain object's composition, and persist
// the change.
if (id) {
$q.when(action && action.perform()).then(function (result) {
broadcastDrop(id, event);
});
}
}
// TODO: Alert user if drag and drop is not allowed
}
// We can only handle drops if we have access to actions...

Some files were not shown because too many files have changed in this diff Show More