Compare commits
186 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7ccf5105b | ||
|
|
73f8a06695 | ||
|
|
9cc0c0b06f | ||
|
|
c703714cb3 | ||
|
|
b48a07cd3e | ||
|
|
8c29c8ed0e | ||
|
|
5763511ec8 | ||
|
|
2accf21518 | ||
|
|
28c42fcd4c | ||
|
|
1efa97e6f5 | ||
|
|
756f728865 | ||
|
|
d8276c532b | ||
|
|
fc0bfa77db | ||
|
|
12c6e53939 | ||
|
|
4f716ad5c5 | ||
|
|
8093fcbda1 | ||
|
|
0ea5721f76 | ||
|
|
d902943552 | ||
|
|
5f7c8ccadb | ||
|
|
520d17f9db | ||
|
|
7532db5f49 | ||
|
|
ebd8fdeee3 | ||
|
|
f738f84075 | ||
|
|
cc19a0acba | ||
|
|
134b749bbf | ||
|
|
36d06e8b54 | ||
|
|
5520d90984 | ||
|
|
77b0086d18 | ||
|
|
146e948097 | ||
|
|
669b434c36 | ||
|
|
431c74ca49 | ||
|
|
cd0c0f77cc | ||
|
|
8cba321886 | ||
|
|
dd83816035 | ||
|
|
1ca2b769d9 | ||
|
|
a1d1261179 | ||
|
|
99048a4ee3 | ||
|
|
553b17fafe | ||
|
|
c4aff95341 | ||
|
|
13095b4135 | ||
|
|
fd927d4c03 | ||
|
|
445f22ccb0 | ||
|
|
1ad0bf337c | ||
|
|
73dc16d398 | ||
|
|
bebe53820f | ||
|
|
dfe909d6b5 | ||
|
|
3cf62ded08 | ||
|
|
6cbd3e5fae | ||
|
|
3050b265fb | ||
|
|
5104a7990a | ||
|
|
571beb8df2 | ||
|
|
bea5002752 | ||
|
|
d04c5e6858 | ||
|
|
0d1f3bf87a | ||
|
|
b632926d8e | ||
|
|
78f3f8367e | ||
|
|
85ac4a9a32 | ||
|
|
ef527df381 | ||
|
|
c2868a4573 | ||
|
|
77c66053f3 | ||
|
|
0891e15936 | ||
|
|
2979ee90a3 | ||
|
|
77c399f2a2 | ||
|
|
fe8543158e | ||
|
|
a4f3e0d776 | ||
|
|
866c8882ca | ||
|
|
ad7d3d642e | ||
|
|
333f7cb848 | ||
|
|
f198c281bc | ||
|
|
23de3917bb | ||
|
|
badaca53d3 | ||
|
|
00ac249ee2 | ||
|
|
00aa6821d1 | ||
|
|
e33485ec59 | ||
|
|
afb1202865 | ||
|
|
f5a4a370f9 | ||
|
|
2848a8458b | ||
|
|
cbaf45afe9 | ||
|
|
7a677062e4 | ||
|
|
a7153f320f | ||
|
|
b3da6edd0c | ||
|
|
ff1fd26efc | ||
|
|
4ced6c44a6 | ||
|
|
67f627b51f | ||
|
|
1d83516982 | ||
|
|
9e64dfe3b9 | ||
|
|
09f5fa42ab | ||
|
|
54a077a4e2 | ||
|
|
13525a67c2 | ||
|
|
cc6b6538d5 | ||
|
|
0c7de98195 | ||
|
|
404d1e7801 | ||
|
|
1214a32c26 | ||
|
|
6bd8e7a47c | ||
|
|
825d93cee3 | ||
|
|
9f7dc1da9b | ||
|
|
3d8aec2d01 | ||
|
|
928e31b548 | ||
|
|
f182d1f2c4 | ||
|
|
d238b669a5 | ||
|
|
5d5a7c26c5 | ||
|
|
0b0cee3afb | ||
|
|
0260e6fff4 | ||
|
|
9811443c71 | ||
|
|
7dc13dab66 | ||
|
|
e67a2e63cf | ||
|
|
f4e53a946d | ||
|
|
de71bde62f | ||
|
|
8f24e014e0 | ||
|
|
190f5fd0ea | ||
|
|
ad29fb0f92 | ||
|
|
fcd073c010 | ||
|
|
071368c3b9 | ||
|
|
7a97588aa5 | ||
|
|
f776561303 | ||
|
|
e34fe1a289 | ||
|
|
70d9587c9b | ||
|
|
9a78b63065 | ||
|
|
6c497f3c36 | ||
|
|
d951b794e3 | ||
|
|
797046aca4 | ||
|
|
cf76583ed7 | ||
|
|
6f28ab0145 | ||
|
|
9ebf157ec0 | ||
|
|
493c63be44 | ||
|
|
f29951140f | ||
|
|
d0b5bb2d21 | ||
|
|
cd98886a43 | ||
|
|
4549828cae | ||
|
|
d0478c3433 | ||
|
|
53369ec0dc | ||
|
|
de99969f0a | ||
|
|
24449d2dcc | ||
|
|
f42c5ca1e5 | ||
|
|
890aafc203 | ||
|
|
2a14cf2dfc | ||
|
|
62962e119e | ||
|
|
2229e868ce | ||
|
|
8d209f4d19 | ||
|
|
86bb89a162 | ||
|
|
2758250833 | ||
|
|
7d20351a6a | ||
|
|
78fae345da | ||
|
|
4c79c9a1b1 | ||
|
|
2ec9956d44 | ||
|
|
e3b191b5dc | ||
|
|
a4dda695dd | ||
|
|
0d710209b1 | ||
|
|
fdbc91131b | ||
|
|
d2dfec3ce7 | ||
|
|
351181d38e | ||
|
|
760f4b818f | ||
|
|
c026bfa17d | ||
|
|
47b97a504e | ||
|
|
29c460556a | ||
|
|
4d276888e1 | ||
|
|
142af3db77 | ||
|
|
b66759e519 | ||
|
|
c58ffb4a52 | ||
|
|
600ff1a3ee | ||
|
|
77d11e1bcf | ||
|
|
d158aa6028 | ||
|
|
c2985d61b7 | ||
|
|
3ce40ab870 | ||
|
|
bfb19dea74 | ||
|
|
01a6d2e6a7 | ||
|
|
af462ff3ee | ||
|
|
5c1d209eff | ||
|
|
8a76c3a425 | ||
|
|
9ccd0b9188 | ||
|
|
f83588d980 | ||
|
|
a481b377cb | ||
|
|
35ff4efbca | ||
|
|
436e010738 | ||
|
|
bf4765fcb6 | ||
|
|
dbfb8b9861 | ||
|
|
681cd0bb9c | ||
|
|
b668fb58fb | ||
|
|
f74da6b935 | ||
|
|
e4dec21ceb | ||
|
|
fc2860810b | ||
|
|
9d6b70f433 | ||
|
|
57a947eaef | ||
|
|
a18cc50a43 | ||
|
|
91fe3d798f | ||
|
|
e873389655 |
15
README.md
15
README.md
@@ -103,6 +103,21 @@ This build will:
|
||||
|
||||
Run as `mvn clean install`.
|
||||
|
||||
### Building Documentation
|
||||
|
||||
Open MCT Web's documentation is generated by an
|
||||
[npm](https://www.npmjs.com/)-based build:
|
||||
|
||||
* `npm install` _(only needs to run once)_
|
||||
* `npm run docs`
|
||||
|
||||
Documentation will be generated in `target/docs`. Note that diagram
|
||||
generation is dependent on having [Cairo](http://cairographics.org/download/)
|
||||
installed; see
|
||||
[node-canvas](https://github.com/Automattic/node-canvas#installation)'s
|
||||
documentation for help with installation.
|
||||
|
||||
|
||||
# Glossary
|
||||
|
||||
Certain terms are used throughout Open MCT Web with consistent meanings
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"key": "eventGenerator",
|
||||
"name": "Event Message Generator",
|
||||
"glyph": "f",
|
||||
"description": "An event message generator",
|
||||
"description": "For development use. Creates sample event message data that mimics a live data stream.",
|
||||
"features": "creation",
|
||||
"model": {
|
||||
"telemetry": {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Sine Wave Generator",
|
||||
"description": "Example of a component that produces dataa.",
|
||||
"description": "Example of a component that produces data.",
|
||||
"extensions": {
|
||||
"components": [
|
||||
{
|
||||
@@ -21,7 +21,7 @@
|
||||
"key": "generator",
|
||||
"name": "Sine Wave Generator",
|
||||
"glyph": "T",
|
||||
"description": "A sine wave generator",
|
||||
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
||||
"features": "creation",
|
||||
"model": {
|
||||
"telemetry": {
|
||||
@@ -34,6 +34,10 @@
|
||||
{
|
||||
"key": "time",
|
||||
"name": "Time"
|
||||
},
|
||||
{
|
||||
"key": "yesterday",
|
||||
"name": "Yesterday"
|
||||
}
|
||||
],
|
||||
"ranges": [
|
||||
@@ -61,4 +65,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
* Module defining SinewaveTelemetryProvider. Created by vwoeltje on 11/12/14.
|
||||
*/
|
||||
define(
|
||||
["./SinewaveTelemetry"],
|
||||
function (SinewaveTelemetry) {
|
||||
["./SinewaveTelemetrySeries"],
|
||||
function (SinewaveTelemetrySeries) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
@@ -45,7 +45,7 @@ define(
|
||||
function generateData(request) {
|
||||
return {
|
||||
key: request.key,
|
||||
telemetry: new SinewaveTelemetry(request)
|
||||
telemetry: new SinewaveTelemetrySeries(request)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -112,4 +112,4 @@ define(
|
||||
|
||||
return SinewaveTelemetryProvider;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
@@ -29,35 +29,47 @@ define(
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var firstObservedTime = Date.now();
|
||||
var ONE_DAY = 60 * 60 * 24,
|
||||
firstObservedTime = Math.floor(Date.now() / 1000) - ONE_DAY;
|
||||
|
||||
/**
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function SinewaveTelemetry(request) {
|
||||
var latestObservedTime = Date.now(),
|
||||
count = Math.floor((latestObservedTime - firstObservedTime) / 1000),
|
||||
period = request.period || 30,
|
||||
generatorData = {};
|
||||
function SinewaveTelemetrySeries(request) {
|
||||
var timeOffset = (request.domain === 'yesterday') ? ONE_DAY : 0,
|
||||
latestTime = Math.floor(Date.now() / 1000) - timeOffset,
|
||||
firstTime = firstObservedTime - timeOffset,
|
||||
endTime = (request.end !== undefined) ?
|
||||
Math.floor(request.end / 1000) : latestTime,
|
||||
count = Math.min(endTime, latestTime) - firstTime,
|
||||
period = +request.period || 30,
|
||||
generatorData = {},
|
||||
requestStart = (request.start === undefined) ? firstTime :
|
||||
Math.max(Math.floor(request.start / 1000), firstTime),
|
||||
offset = requestStart - firstTime;
|
||||
|
||||
if (request.size !== undefined) {
|
||||
offset = Math.max(offset, count - request.size);
|
||||
}
|
||||
|
||||
generatorData.getPointCount = function () {
|
||||
return count;
|
||||
return count - offset;
|
||||
};
|
||||
|
||||
generatorData.getDomainValue = function (i, domain) {
|
||||
return i * 1000 +
|
||||
(domain !== 'delta' ? firstObservedTime : 0);
|
||||
return (i + offset) * 1000 + firstTime * 1000 -
|
||||
(domain === 'yesterday' ? ONE_DAY : 0);
|
||||
};
|
||||
|
||||
generatorData.getRangeValue = function (i, range) {
|
||||
range = range || "sin";
|
||||
return Math[range](i * Math.PI * 2 / period);
|
||||
return Math[range]((i + offset) * Math.PI * 2 / period);
|
||||
};
|
||||
|
||||
return generatorData;
|
||||
}
|
||||
|
||||
return SinewaveTelemetry;
|
||||
return SinewaveTelemetrySeries;
|
||||
}
|
||||
);
|
||||
);
|
||||
@@ -14,6 +14,7 @@
|
||||
{
|
||||
"key": "imagery",
|
||||
"name": "Example Imagery",
|
||||
"description": "For development use. Creates example imagery data that mimics a live imagery stream.",
|
||||
"glyph": "T",
|
||||
"features": "creation",
|
||||
"model": {
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
{
|
||||
"implementation": "WatchIndicator.js",
|
||||
"depends": ["$interval", "$rootScope"]
|
||||
},
|
||||
{
|
||||
"implementation": "DigestIndicator.js",
|
||||
"depends": ["$interval", "$rootScope"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,50 +19,59 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise*/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* Module defining NavigateAction. Created by vwoeltje on 11/10/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The `back` action navigates to the contextual parent of a
|
||||
* specific domain object.
|
||||
* @memberof platform/commonUI/browse
|
||||
* Displays the number of digests that have occurred since the
|
||||
* indicator was first instantiated.
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
* @param $interval Angular's $interval
|
||||
* @implements {Indicator}
|
||||
*/
|
||||
function BackAction(context) {
|
||||
this.domainObject = context.domainObject;
|
||||
function DigestIndicator($interval, $rootScope) {
|
||||
var digests = 0,
|
||||
displayed = 0,
|
||||
start = Date.now();
|
||||
|
||||
function update() {
|
||||
var secs = (Date.now() - start) / 1000;
|
||||
displayed = Math.round(digests / secs);
|
||||
}
|
||||
|
||||
function increment() {
|
||||
digests += 1;
|
||||
}
|
||||
|
||||
$rootScope.$watch(increment);
|
||||
|
||||
// Update state every second
|
||||
$interval(update, 1000);
|
||||
|
||||
// Provide initial state, too
|
||||
update();
|
||||
|
||||
return {
|
||||
getGlyph: function () {
|
||||
return ".";
|
||||
},
|
||||
getGlyphClass: function () {
|
||||
return undefined;
|
||||
},
|
||||
getText: function () {
|
||||
return displayed + " digests/sec";
|
||||
},
|
||||
getDescription: function () {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the object described in the context.
|
||||
* @returns {Promise} a promise that is resolved once the
|
||||
* navigation has been updated
|
||||
*/
|
||||
BackAction.prototype.perform = function () {
|
||||
var parent = this.domainObject.getCapability("context")
|
||||
.getParent();
|
||||
return parent.getCapability("action").perform("navigate");
|
||||
};
|
||||
return DigestIndicator;
|
||||
|
||||
/**
|
||||
* Navigate as an action is only applicable when a domain object
|
||||
* is described in the action context.
|
||||
* @param {ActionContext} context the context in which the action
|
||||
* will be performed
|
||||
* @returns {boolean} true if applicable
|
||||
*/
|
||||
BackAction.appliesTo = function (context) {
|
||||
return context.domainObject !== undefined &&
|
||||
context.domainObject.hasCapability("context");
|
||||
};
|
||||
|
||||
return BackAction;
|
||||
}
|
||||
);
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"extensions": {
|
||||
"routes": [
|
||||
{
|
||||
"when": "/cli",
|
||||
"templateUrl": "templates/cli.html"
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "CLIController",
|
||||
"implementation": "CLIController.js",
|
||||
"depends": [ "$scope", "navigationService", "objectService" ]
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "stylesheets/cli.css"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
.iw-container {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.iw-stdin {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 30px;
|
||||
width: calc(100% - 8px);
|
||||
margin: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.iw-stdout {
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
top: 12px;
|
||||
bottom: 44px;
|
||||
border: 1px #211 solid;
|
||||
border-radius: 12px;
|
||||
padding: 8px;
|
||||
background: #302;
|
||||
overflow: auto;
|
||||
box-shadow: inset 0px 2px 8px 0px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.iw-stdout span {
|
||||
display: block;
|
||||
font-family: monospace;
|
||||
color: #FD9;
|
||||
font-size: 16px;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
min-height: 1em;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.iw-stdout span.iw-user-input {
|
||||
color: gray;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<div class="abs holder-all browse-mode" ng-controller="CLIController">
|
||||
<div class="iw-container">
|
||||
<div class="iw-stdout" mct-scroll-y="stdoutScroll">
|
||||
<span ng-repeat="line in stdout track by $index"
|
||||
class="{{line.cssClass}}"
|
||||
ng-bind="line.text">
|
||||
</span>
|
||||
</div>
|
||||
<form ng-submit="enter(stdin)">
|
||||
<input type="text" class="iw-stdin" ng-model="stdin" autofocus>
|
||||
</form>
|
||||
</div>
|
||||
<mct-include key="'bottombar'"></mct-include>
|
||||
</div>
|
||||
|
||||
@@ -1,177 +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.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define(function () {
|
||||
'use strict';
|
||||
return function CLIController($scope, navigationService, objectService) {
|
||||
var unlistenToMutation,
|
||||
currentComposition = [];
|
||||
|
||||
function print(str, cssClass) {
|
||||
$scope.stdout.push({
|
||||
text: str,
|
||||
cssClass: cssClass
|
||||
});
|
||||
$scope.stdoutScroll = Number.MAX_VALUE;
|
||||
}
|
||||
|
||||
function pad(str, length) {
|
||||
while (str.length < length) {
|
||||
str += " ";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function summarize(domainObject) {
|
||||
var type = domainObject.getCapability("type"),
|
||||
typeName = type ? type.getName() : "Object",
|
||||
location = domainObject.getCapability('location'),
|
||||
isLink = (location && location.isLink()),
|
||||
suffix = isLink ? " (link)" : "";
|
||||
return "[" + typeName + "] " + domainObject.getModel().name + suffix;
|
||||
}
|
||||
|
||||
function printComposition(domainObject) {
|
||||
return domainObject.useCapability("composition").then(function (c) {
|
||||
currentComposition = c;
|
||||
c.forEach(function (childObject, i) {
|
||||
print(i + ") " + summarize(childObject));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function printObject(domainObject, callback) {
|
||||
// Exclude the root object; nobody wants to see that
|
||||
if (domainObject.hasCapability("context")) {
|
||||
print(summarize(domainObject));
|
||||
}
|
||||
if (domainObject.hasCapability('composition')) {
|
||||
printComposition(domainObject).then(callback);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
function unlisten() {
|
||||
if (unlistenToMutation) {
|
||||
unlistenToMutation();
|
||||
unlistenToMutation = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function navChange(domainObject) {
|
||||
unlisten();
|
||||
unlistenToMutation = domainObject.getCapability("mutation")
|
||||
.listen(function () { printObject(domainObject); });
|
||||
printObject(domainObject);
|
||||
}
|
||||
|
||||
function findTarget(id) {
|
||||
if (id === "this") {
|
||||
return navigationService.getNavigation();
|
||||
} else {
|
||||
return currentComposition[parseInt(id, 10)];
|
||||
}
|
||||
}
|
||||
|
||||
function listActions(domainObject, index) {
|
||||
// Don't show actions for the root
|
||||
if (!domainObject.hasCapability('context')) {
|
||||
return;
|
||||
}
|
||||
|
||||
domainObject.getCapability('action').getActions().forEach(function (a) {
|
||||
var metadata = a.getMetadata(),
|
||||
desc = metadata.description,
|
||||
suffix = index !== undefined ? (" " + index) : "";
|
||||
print(pad(metadata.key + suffix, 32) + (desc || ""));
|
||||
});
|
||||
}
|
||||
|
||||
function performAction(domainObject, action) {
|
||||
domainObject.getCapability('action').perform(action);
|
||||
}
|
||||
|
||||
function handleInput(input) {
|
||||
var parts = input.split(" "),
|
||||
targetObject;
|
||||
|
||||
if (input.length === 0) {
|
||||
targetObject = navigationService.getNavigation();
|
||||
if (targetObject) {
|
||||
printObject(targetObject, function () {
|
||||
print("");
|
||||
listActions(targetObject);
|
||||
});
|
||||
}
|
||||
return;
|
||||
} else if (parts.length === 1) {
|
||||
if (isNaN(parseInt(parts[0], 10))) {
|
||||
targetObject = navigationService.getNavigation();
|
||||
performAction(targetObject, parts[0]);
|
||||
return;
|
||||
}
|
||||
targetObject = findTarget(parts[0]);
|
||||
if (targetObject) {
|
||||
listActions(targetObject, parts[0]);
|
||||
return;
|
||||
}
|
||||
} else if (parts.length === 2) {
|
||||
targetObject = findTarget(parts[1]);
|
||||
if (targetObject) {
|
||||
performAction(targetObject, parts[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Any parse-able input should have returned already.
|
||||
print("SYNTAX ERROR. READY.");
|
||||
}
|
||||
|
||||
if (!navigationService.getNavigation()) {
|
||||
objectService.getObjects(["ROOT"]).then(function (objects) {
|
||||
navigationService.setNavigation(objects.ROOT);
|
||||
});
|
||||
}
|
||||
|
||||
navigationService.addListener(navChange);
|
||||
|
||||
$scope.stdout = [];
|
||||
$scope.stdin = "";
|
||||
$scope.stdoutScroll = 0;
|
||||
|
||||
$scope.enter = function (input) {
|
||||
$scope.stdin = "";
|
||||
print("");
|
||||
print(input, "iw-user-input");
|
||||
print("");
|
||||
|
||||
handleInput(input);
|
||||
};
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
navigationService.removeListener(navChange);
|
||||
unlisten();
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -105,15 +105,9 @@
|
||||
"actions": [
|
||||
{
|
||||
"key": "navigate",
|
||||
"description": "Browse to this object.",
|
||||
"implementation": "navigation/NavigateAction.js",
|
||||
"depends": [ "navigationService", "$q" ]
|
||||
},
|
||||
{
|
||||
"key": "back",
|
||||
"implementation": "navigation/BackAction.js",
|
||||
"description": "Navigate to the parent of this object."
|
||||
},
|
||||
{
|
||||
"key": "window",
|
||||
"name": "Open In New Tab",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<a
|
||||
class='type-icon icon ui-symbol s-back'
|
||||
ng-show="context.getPath().length > 2"
|
||||
ng-click="domainObject.getCapability('action').perform('back')">
|
||||
ng-click="context.getParent().getCapability('action').perform('navigate')">
|
||||
{
|
||||
</a>
|
||||
|
||||
|
||||
@@ -42,9 +42,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='object-holder abs vscroll'>
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs object-holder">
|
||||
</mct-representation>
|
||||
</span>
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
<mct-split-pane class='contents abs' anchor='left'>
|
||||
<div class='split-pane-component treeview pane left'>
|
||||
<div class="holder abs l-mobile">
|
||||
<mct-representation key="'create-button'" mct-object="navigatedObject">
|
||||
<mct-representation key="'create-button'"
|
||||
mct-object="navigatedObject"
|
||||
mct-device="desktop">
|
||||
</mct-representation>
|
||||
<div class='holder search-holder abs'
|
||||
ng-class="{active: treeModel.search}">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="menu-element wrapper" ng-controller="ClickAwayController as createController">
|
||||
<div class="s-menu major create-btn" ng-click="createController.toggle()">
|
||||
<div class="s-menu-btn major create-btn" ng-click="createController.toggle()">
|
||||
<span class="ui-symbol icon type-icon">+</span>
|
||||
<span class="title-label">Create</span>
|
||||
</div>
|
||||
|
||||
@@ -53,12 +53,11 @@ define(
|
||||
*/
|
||||
function CreateAction(type, parent, context, dialogService, creationService, policyService) {
|
||||
this.metadata = {
|
||||
key: 'create.' + type.getKey(),
|
||||
key: 'create',
|
||||
glyph: type.getGlyph(),
|
||||
name: type.getName(),
|
||||
type: type.getKey(),
|
||||
description: type.getDescription(),
|
||||
category: [ 'creation' ],
|
||||
context: context
|
||||
};
|
||||
|
||||
|
||||
@@ -63,10 +63,7 @@ define(
|
||||
// domain object to serve as the container for the
|
||||
// newly-created object (although the user may later
|
||||
// make a different selection)
|
||||
if (!destination) {
|
||||
return [];
|
||||
}
|
||||
if (context.category && context.category !== "creation") {
|
||||
if (key !== 'create' || !destination) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ define(
|
||||
// Update the set of Create actions
|
||||
function refreshActions() {
|
||||
$scope.createActions = $scope.action ?
|
||||
$scope.action.getActions({ category: "creation" }) :
|
||||
$scope.action.getActions('create') :
|
||||
[];
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +53,9 @@ define(
|
||||
// based on whether or not we are currently
|
||||
// full screen.
|
||||
var metadata = Object.create(FullscreenAction);
|
||||
metadata.key = "fullscreen";
|
||||
metadata.glyph = screenfull.isFullscreen ? "_" : "z";
|
||||
metadata.description = screenfull.isFullscreen ?
|
||||
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
|
||||
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
|
||||
metadata.group = "windowing";
|
||||
metadata.context = this.context;
|
||||
return metadata;
|
||||
|
||||
@@ -30,12 +30,11 @@
|
||||
structure="toolbar.structure"
|
||||
ng-model="toolbar.state">
|
||||
</mct-toolbar>
|
||||
<div class='holder abs object-holder work-area'>
|
||||
<mct-representation key="representation.selected.key"
|
||||
toolbar="toolbar"
|
||||
mct-object="representation.selected.key && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<mct-representation key="representation.selected.key"
|
||||
toolbar="toolbar"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="holder abs object-holder work-area">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<mct-splitter></mct-splitter>
|
||||
<div
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
"key": "urlService",
|
||||
"implementation": "services/UrlService.js",
|
||||
"depends": [ "$location" ]
|
||||
},
|
||||
{
|
||||
"key": "popupService",
|
||||
"implementation": "services/PopupService.js",
|
||||
"depends": [ "$document", "$window" ]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
@@ -45,6 +50,16 @@
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "TimeRangeController",
|
||||
"implementation": "controllers/TimeRangeController.js",
|
||||
"depends": [ "$scope", "now" ]
|
||||
},
|
||||
{
|
||||
"key": "DateTimePickerController",
|
||||
"implementation": "controllers/DateTimePickerController.js",
|
||||
"depends": [ "$scope", "now" ]
|
||||
},
|
||||
{
|
||||
"key": "TreeNodeController",
|
||||
"implementation": "controllers/TreeNodeController.js",
|
||||
@@ -105,11 +120,21 @@
|
||||
"implementation": "directives/MCTDrag.js",
|
||||
"depends": [ "$document" ]
|
||||
},
|
||||
{
|
||||
"key": "mctClickElsewhere",
|
||||
"implementation": "directives/MCTClickElsewhere.js",
|
||||
"depends": [ "$document" ]
|
||||
},
|
||||
{
|
||||
"key": "mctResize",
|
||||
"implementation": "directives/MCTResize.js",
|
||||
"depends": [ "$timeout" ]
|
||||
},
|
||||
{
|
||||
"key": "mctPopup",
|
||||
"implementation": "directives/MCTPopup.js",
|
||||
"depends": [ "$compile", "popupService" ]
|
||||
},
|
||||
{
|
||||
"key": "mctScrollX",
|
||||
"implementation": "directives/MCTScroll.js",
|
||||
@@ -213,6 +238,10 @@
|
||||
{
|
||||
"key": "selector",
|
||||
"templateUrl": "templates/controls/selector.html"
|
||||
},
|
||||
{
|
||||
"key": "datetime-picker",
|
||||
"templateUrl": "templates/controls/datetime-picker.html"
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "WTD Symbols v24",
|
||||
"lastOpened": 1441992412958,
|
||||
"created": 1441992410384
|
||||
"name": "WTD Symbols v25",
|
||||
"lastOpened": 1444865544920,
|
||||
"created": 1444865541293
|
||||
},
|
||||
"iconSets": [
|
||||
{
|
||||
"selection": [
|
||||
{
|
||||
"order": 86,
|
||||
"order": 108,
|
||||
"id": 88,
|
||||
"prevSize": 32,
|
||||
"code": 58897,
|
||||
"name": "icon-dataset",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 90,
|
||||
"id": 87,
|
||||
"prevSize": 32,
|
||||
"code": 58896,
|
||||
"name": "icon-bell",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 91,
|
||||
"id": 86,
|
||||
"prevSize": 32,
|
||||
"code": 58889,
|
||||
"name": "icon-hourglass",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 92,
|
||||
"id": 85,
|
||||
"prevSize": 32,
|
||||
"code": 58888,
|
||||
@@ -18,119 +42,119 @@
|
||||
58890
|
||||
],
|
||||
"name": "icon-info-v15",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 82,
|
||||
"order": 93,
|
||||
"id": 84,
|
||||
"prevSize": 32,
|
||||
"code": 58887,
|
||||
"name": "icon-x-in-circle",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 77,
|
||||
"order": 94,
|
||||
"id": 83,
|
||||
"prevSize": 32,
|
||||
"code": 58881,
|
||||
"name": "icon-datatable",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 78,
|
||||
"order": 95,
|
||||
"id": 82,
|
||||
"prevSize": 32,
|
||||
"code": 58882,
|
||||
"name": "icon-tabular-scrolling",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 79,
|
||||
"order": 96,
|
||||
"id": 81,
|
||||
"prevSize": 32,
|
||||
"code": 58884,
|
||||
"name": "icon-tabular",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 80,
|
||||
"order": 97,
|
||||
"id": 80,
|
||||
"prevSize": 32,
|
||||
"code": 58885,
|
||||
"name": "icon-calendar",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 83,
|
||||
"order": 98,
|
||||
"id": 78,
|
||||
"prevSize": 32,
|
||||
"code": 58886,
|
||||
"name": "icon-paint-bucket",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 1,
|
||||
"order": 99,
|
||||
"id": 75,
|
||||
"prevSize": 32,
|
||||
"code": 123,
|
||||
"name": "icon-pointer-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 3,
|
||||
"order": 100,
|
||||
"id": 74,
|
||||
"prevSize": 32,
|
||||
"code": 125,
|
||||
"name": "icon-pointer-right",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 4,
|
||||
"order": 101,
|
||||
"id": 73,
|
||||
"prevSize": 32,
|
||||
"code": 80,
|
||||
"name": "icon-person",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 5,
|
||||
"order": 102,
|
||||
"id": 72,
|
||||
"prevSize": 32,
|
||||
"code": 232,
|
||||
"name": "icon-chain-links",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 6,
|
||||
"order": 103,
|
||||
"id": 71,
|
||||
"prevSize": 32,
|
||||
"code": 115,
|
||||
"name": "icon-database-in-brackets",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 7,
|
||||
"order": 104,
|
||||
"id": 70,
|
||||
"prevSize": 32,
|
||||
"code": 114,
|
||||
"name": "icon-refresh",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 8,
|
||||
"order": 105,
|
||||
"id": 69,
|
||||
"prevSize": 32,
|
||||
"code": 108,
|
||||
"name": "icon-lock",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 9,
|
||||
"order": 106,
|
||||
"id": 68,
|
||||
"prevSize": 32,
|
||||
"code": 51,
|
||||
"name": "icon-box-with-dashed-lines",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 10,
|
||||
@@ -138,7 +162,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58880,
|
||||
"name": "icon-box-with-arrow-cursor",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 11,
|
||||
@@ -146,7 +170,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 65,
|
||||
"name": "icon-activity-mode",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 12,
|
||||
@@ -154,15 +178,15 @@
|
||||
"prevSize": 32,
|
||||
"code": 97,
|
||||
"name": "icon-activity",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 13,
|
||||
"order": 87,
|
||||
"id": 64,
|
||||
"prevSize": 32,
|
||||
"code": 33,
|
||||
"name": "icon-alert-rect",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 14,
|
||||
@@ -170,7 +194,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58883,
|
||||
"name": "icon-alert-triangle",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 15,
|
||||
@@ -178,7 +202,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 238,
|
||||
"name": "icon-arrow-double-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 16,
|
||||
@@ -186,7 +210,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 235,
|
||||
"name": "icon-arrow-double-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 2,
|
||||
@@ -194,7 +218,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 118,
|
||||
"name": "icon-arrow-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 19,
|
||||
@@ -202,7 +226,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 60,
|
||||
"name": "icon-arrow-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 20,
|
||||
@@ -210,7 +234,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 62,
|
||||
"name": "icon-arrow-right",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 21,
|
||||
@@ -218,7 +242,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 236,
|
||||
"name": "icon-arrow-tall-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 22,
|
||||
@@ -226,7 +250,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 237,
|
||||
"name": "icon-arrow-tall-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 23,
|
||||
@@ -234,7 +258,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 94,
|
||||
"name": "icon-arrow-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 24,
|
||||
@@ -242,7 +266,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 73,
|
||||
"name": "icon-arrows-out",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 25,
|
||||
@@ -250,7 +274,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58893,
|
||||
"name": "icon-arrows-right-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 33,
|
||||
@@ -258,7 +282,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 53,
|
||||
"name": "icon-arrows-up-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 26,
|
||||
@@ -266,7 +290,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 42,
|
||||
"name": "icon-asterisk",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 27,
|
||||
@@ -274,7 +298,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 72,
|
||||
"name": "icon-autoflow-tabular",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 28,
|
||||
@@ -282,7 +306,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 224,
|
||||
"name": "icon-box",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 29,
|
||||
@@ -290,7 +314,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 50,
|
||||
"name": "icon-check",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 30,
|
||||
@@ -298,7 +322,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 67,
|
||||
"name": "icon-clock",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 31,
|
||||
@@ -306,7 +330,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 46,
|
||||
"name": "icon-connectivity",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 32,
|
||||
@@ -314,7 +338,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 100,
|
||||
"name": "icon-database-query",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 17,
|
||||
@@ -322,7 +346,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 68,
|
||||
"name": "icon-database",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 35,
|
||||
@@ -330,7 +354,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 81,
|
||||
"name": "icon-dictionary",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 36,
|
||||
@@ -338,7 +362,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 242,
|
||||
"name": "icon-duplicate",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 37,
|
||||
@@ -346,7 +370,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 102,
|
||||
"name": "icon-folder-new",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 38,
|
||||
@@ -354,7 +378,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 70,
|
||||
"name": "icon-folder",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 39,
|
||||
@@ -362,7 +386,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 95,
|
||||
"name": "icon-fullscreen-collapse",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 40,
|
||||
@@ -370,7 +394,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 122,
|
||||
"name": "icon-fullscreen-expand",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 41,
|
||||
@@ -378,7 +402,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 71,
|
||||
"name": "icon-gear",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 49,
|
||||
@@ -386,7 +410,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 227,
|
||||
"name": "icon-image",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 42,
|
||||
@@ -394,7 +418,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 225,
|
||||
"name": "icon-layers",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 43,
|
||||
@@ -402,7 +426,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 76,
|
||||
"name": "icon-layout",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 44,
|
||||
@@ -410,7 +434,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 226,
|
||||
"name": "icon-line-horz",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 75,
|
||||
@@ -418,7 +442,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 244,
|
||||
"name": "icon-link",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 46,
|
||||
@@ -426,7 +450,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 88,
|
||||
"name": "icon-magnify-in",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 47,
|
||||
@@ -434,7 +458,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 89,
|
||||
"name": "icon-magnify-out",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 48,
|
||||
@@ -442,7 +466,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 77,
|
||||
"name": "icon-magnify",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 34,
|
||||
@@ -450,7 +474,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 109,
|
||||
"name": "icon-menu",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 50,
|
||||
@@ -458,7 +482,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 243,
|
||||
"name": "icon-move",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 51,
|
||||
@@ -466,7 +490,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 121,
|
||||
"name": "icon-new-window",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 52,
|
||||
@@ -474,7 +498,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 111,
|
||||
"name": "icon-object",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 73,
|
||||
@@ -482,7 +506,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 63,
|
||||
"name": "icon-object-unknown",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 53,
|
||||
@@ -490,7 +514,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 86,
|
||||
"name": "icon-packet",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 54,
|
||||
@@ -498,7 +522,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 234,
|
||||
"name": "icon-page",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 55,
|
||||
@@ -506,7 +530,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 241,
|
||||
"name": "icon-pause",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 56,
|
||||
@@ -514,7 +538,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 112,
|
||||
"name": "icon-pencil",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 65,
|
||||
@@ -522,7 +546,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 79,
|
||||
"name": "icon-people",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 57,
|
||||
@@ -530,7 +554,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 239,
|
||||
"name": "icon-play",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 58,
|
||||
@@ -538,7 +562,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 233,
|
||||
"name": "icon-plot-resource",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 59,
|
||||
@@ -546,7 +570,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 43,
|
||||
"name": "icon-plus",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 60,
|
||||
@@ -554,7 +578,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 45,
|
||||
"name": "icon-minus",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 61,
|
||||
@@ -562,7 +586,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 54,
|
||||
"name": "icon-sine",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 62,
|
||||
@@ -570,7 +594,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 228,
|
||||
"name": "icon-T",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 63,
|
||||
@@ -578,7 +602,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 116,
|
||||
"name": "icon-telemetry-panel",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 64,
|
||||
@@ -586,7 +610,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 84,
|
||||
"name": "icon-telemetry",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 18,
|
||||
@@ -594,7 +618,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 246,
|
||||
"name": "icon-thumbs-strip",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 67,
|
||||
@@ -602,7 +626,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 83,
|
||||
"name": "icon-timeline",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 68,
|
||||
@@ -610,7 +634,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 245,
|
||||
"name": "icon-timer",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 69,
|
||||
@@ -618,7 +642,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 90,
|
||||
"name": "icon-trash",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 70,
|
||||
@@ -626,7 +650,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 229,
|
||||
"name": "icon-two-parts-both",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 71,
|
||||
@@ -634,7 +658,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 231,
|
||||
"name": "icon-two-parts-one-only",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 72,
|
||||
@@ -642,7 +666,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 120,
|
||||
"name": "icon-x-heavy",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 66,
|
||||
@@ -650,7 +674,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58946,
|
||||
"name": "icon-x",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
}
|
||||
],
|
||||
"id": 2,
|
||||
@@ -665,6 +689,74 @@
|
||||
"height": 1024,
|
||||
"prevSize": 32,
|
||||
"icons": [
|
||||
{
|
||||
"id": 88,
|
||||
"paths": [
|
||||
"M896 192h-320c-16.4-16.4-96.8-96.8-109.2-109.2l-37.4-37.4c-25-25-74.2-45.4-109.4-45.4h-256c-35.2 0-64 28.8-64 64v384c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v-128c0-70.4-57.6-128-128-128z",
|
||||
"M896 448h-768c-70.4 0-128 57.6-128 128v320c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-320c0-70.4-57.6-128-128-128zM320 896h-128v-320h128v320zM576 896h-128v-320h128v320zM832 896h-128v-320h128v320z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-dataset"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 87,
|
||||
"paths": [
|
||||
"M512 1024c106 0 192-86 192-192h-384c0 106 86 192 192 192z",
|
||||
"M896 448v-64c0-212-172-384-384-384s-384 172-384 384v64c0 70.6-57.4 128-128 128v128h1024v-128c-70.6 0-128-57.4-128-128z"
|
||||
],
|
||||
"attrs": [
|
||||
{
|
||||
"fill": "rgb(6, 161, 75)"
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6, 161, 75)"
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-bell"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 86,
|
||||
"paths": [
|
||||
"M1024 0h-1024c0 282.8 229.2 512 512 512s512-229.2 512-512zM512 384c-102.6 0-199-40-271.6-112.4-41.2-41.2-72-90.2-90.8-143.6h724.6c-18.8 53.4-49.6 102.4-90.8 143.6-72.4 72.4-168.8 112.4-271.4 112.4z",
|
||||
"M512 512c-282.8 0-512 229.2-512 512h1024c0-282.8-229.2-512-512-512z"
|
||||
],
|
||||
"attrs": [
|
||||
{
|
||||
"fill": "rgb(6, 161, 75)"
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6, 161, 75)"
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-hourglass"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 85,
|
||||
"paths": [
|
||||
@@ -698,7 +790,8 @@
|
||||
"icon-x-in-circle"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"16161751": []
|
||||
"16161751": [],
|
||||
"125525525516161751": []
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -899,6 +992,11 @@
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"125525525516161751": [
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -1051,18 +1149,28 @@
|
||||
{
|
||||
"id": 67,
|
||||
"paths": [
|
||||
"M832 512.4c0-0.2 0-0.2 0-0.4v-320c0-105.6-86.4-192-192-192h-448c-105.6 0-192 86.4-192 192v320c0 105.6 86.4 192 192 192h263.6l-197.2-445.6 573.6 254z",
|
||||
"M766.8 659.8l193.8-20.4-576.6-255.4 255.4 576.6 20.4-193.8 257 257.2 107.2-107.2z"
|
||||
"M894-2h-768c-70.4 0-128 57.6-128 128v768c0 70.4 57.6 128 128 128h400c-2.2-3.8-4-7.6-5.8-11.4l-255.2-576.8c-21.4-48.4-10.8-105 26.6-142.4 24.4-24.4 57.2-37.4 90.4-37.4 17.4 0 35.2 3.6 51.8 11l576.6 255.4c4 1.8 7.8 3.8 11.4 5.8v-400.2c0.2-70.4-57.4-128-127.8-128z",
|
||||
"M958.6 637.4l-576.6-255.4 255.4 576.6 64.6-128.6 192 192 128-128-192-192z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{}
|
||||
{
|
||||
"fill": "rgb(0, 0, 0)"
|
||||
},
|
||||
{
|
||||
"fill": "rgb(0, 0, 0)"
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-box-with-arrow-cursor"
|
||||
]
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 66,
|
||||
@@ -1338,6 +1446,9 @@
|
||||
"colorPermutations": {
|
||||
"16161751": [
|
||||
0
|
||||
],
|
||||
"125525525516161751": [
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -14853,6 +14964,5 @@
|
||||
"gridSize": 16,
|
||||
"showLiga": false
|
||||
},
|
||||
"uid": -1,
|
||||
"time": 1441993324496
|
||||
"uid": -1
|
||||
}
|
||||
Binary file not shown.
@@ -76,7 +76,7 @@
|
||||
<glyph unicode="ô" glyph-name="icon-link" d="M1024 448l-512 512v-307.2l-512-204.8v-256h512v-256z" />
|
||||
<glyph unicode="õ" glyph-name="icon-timer" d="M638 898c0 35.4-28.6 64-64 64h-128c-35.4 0-64-28.6-64-64s28.6-64 64-64h128c35.4 0 64 28.6 64 64zM510 834c-247.4 0-448-200.6-448-448s200.6-448 448-448 448 200.6 448 448-200.6 448-448 448zM510 386h-336c0 185.2 150.8 336 336 336v-336z" />
|
||||
<glyph unicode="ö" glyph-name="icon-thumbs-strip" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
|
||||
<glyph unicode="" glyph-name="icon-box-with-arrow-cursor" d="M832 447.6c0 0.2 0 0.2 0 0.4v320c0 105.6-86.4 192-192 192h-448c-105.6 0-192-86.4-192-192v-320c0-105.6 86.4-192 192-192h263.6l-197.2 445.6 573.6-254zM766.8 300.2l193.8 20.4-576.6 255.4 255.4-576.6 20.4 193.8 257-257.2 107.2 107.2z" />
|
||||
<glyph unicode="" glyph-name="icon-box-with-arrow-cursor" d="M894 962h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h400c-2.2 3.8-4 7.6-5.8 11.4l-255.2 576.8c-21.4 48.4-10.8 105 26.6 142.4 24.4 24.4 57.2 37.4 90.4 37.4 17.4 0 35.2-3.6 51.8-11l576.6-255.4c4-1.8 7.8-3.8 11.4-5.8v400.2c0.2 70.4-57.4 128-127.8 128zM958.6 322.6l-576.6 255.4 255.4-576.6 64.6 128.6 192-192 128 128-192 192z" />
|
||||
<glyph unicode="" glyph-name="icon-datatable" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.8 0-512 86-512 192v-512c0-106 229.2-192 512-192s512 86 512 192v512c0-106-229.2-192-512-192zM896 385v-256c-36.6-15.6-79.8-28.8-128-39.4v256c48.2 10.6 91.4 23.8 128 39.4zM256 345.6v-256c-48.2 10.4-91.4 23.8-128 39.4v256c36.6-15.6 79.8-28.8 128-39.4zM384 70v256c41-4 83.8-6 128-6s87 2.2 128 6v-256c-41-4-83.8-6-128-6s-87 2.2-128 6z" />
|
||||
<glyph unicode="" glyph-name="icon-tabular-scrolling" d="M64 960c-35.2 0-64-28.8-64-64v-192h448v256h-384zM1024 704v192c0 35.2-28.8 64-64 64h-384v-256h448zM0 576v-192c0-35.2 28.8-64 64-64h384v256h-448zM960 320c35.2 0 64 28.8 64 64v192h-448v-256h384zM512-64l-256 256h512z" />
|
||||
<glyph unicode="" glyph-name="icon-alert-triangle" d="M998.208 111.136l-422.702 739.728c-34.928 61.124-92.084 61.124-127.012 0l-422.702-739.728c-34.928-61.126-5.906-111.136 64.494-111.136h843.428c70.4 0 99.422 50.010 64.494 111.136zM512 128c-35.2 0-64 28.8-64 64s28.8 64 64 64 64-28.8 64-64c0-35.2-28.8-64-64-64zM627.448 577.242l-38.898-194.486c-6.902-34.516-41.35-62.756-76.55-62.756s-69.648 28.24-76.552 62.758l-38.898 194.486c-6.902 34.516 16.25 62.756 51.45 62.756h128c35.2 0 58.352-28.24 51.448-62.758z" />
|
||||
@@ -85,6 +85,9 @@
|
||||
<glyph unicode="" glyph-name="icon-paint-bucket" d="M544 736v-224c0-88.4-71.6-160-160-160s-160 71.6-160 160v97.2l-197.4-196.4c-50-50-12.4-215.2 112.4-340s290-162.4 340-112.4l417 423.6-352 352zM896-64c70.6 0 128 57.4 128 128 0 108.6-128 192-128 192s-128-83.4-128-192c0-70.6 57.4-128 128-128zM384 448c-35.4 0-64 28.6-64 64v384c0 35.4 28.6 64 64 64s64-28.6 64-64v-384c0-35.4-28.6-64-64-64z" />
|
||||
<glyph unicode="" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
|
||||
<glyph unicode="" glyph-name="icon-info-v15" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM512 832c70.6 0 128-57.4 128-128s-57.4-128-128-128c-70.6 0-128 57.4-128 128s57.4 128 128 128zM704 128h-384v128h64v256h256v-256h64v-128z" />
|
||||
<glyph unicode="" glyph-name="icon-hourglass" d="M1024 960h-1024c0-282.8 229.2-512 512-512s512 229.2 512 512zM512 576c-102.6 0-199 40-271.6 112.4-41.2 41.2-72 90.2-90.8 143.6h724.6c-18.8-53.4-49.6-102.4-90.8-143.6-72.4-72.4-168.8-112.4-271.4-112.4zM512 448c-282.8 0-512-229.2-512-512h1024c0 282.8-229.2 512-512 512z" />
|
||||
<glyph unicode="" glyph-name="icon-arrows-right-left" d="M1024 448l-448-512v1024zM448 960l-448-512 448-512z" />
|
||||
<glyph unicode="" glyph-name="icon-bell" d="M512-64c106 0 192 86 192 192h-384c0-106 86-192 192-192zM896 512v64c0 212-172 384-384 384s-384-172-384-384v-64c0-70.6-57.4-128-128-128v-128h1024v128c-70.6 0-128 57.4-128 128z" />
|
||||
<glyph unicode="" glyph-name="icon-dataset" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128zM320 64h-128v320h128v-320zM576 64h-128v320h128v-320zM832 64h-128v320h128v-320z" />
|
||||
<glyph unicode="" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 28 KiB |
Binary file not shown.
Binary file not shown.
@@ -45,6 +45,7 @@ $ueEditToolBarH: 25px;
|
||||
$ueBrowseLeftPaneW: 25%;
|
||||
$ueEditLeftPaneW: 75%;
|
||||
$treeSearchInputBarH: 25px;
|
||||
$ueTimeControlH: (33px, 20px, 20px);
|
||||
// Overlay
|
||||
$ovrTopBarH: 60px;
|
||||
$ovrFooterH: 30px;
|
||||
|
||||
@@ -40,11 +40,11 @@
|
||||
|
||||
/************************** HTML ENTITIES */
|
||||
a {
|
||||
color: #ccc;
|
||||
color: $colorA;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
color: $colorAHov;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,14 @@ mct-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrolling {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.vscroll {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
}
|
||||
|
||||
.ui-symbol {
|
||||
&.type-icon {
|
||||
color: $colorObjHdrIc;
|
||||
}
|
||||
&.icon {
|
||||
color: $colorKey;
|
||||
&.alert {
|
||||
@@ -41,6 +44,9 @@
|
||||
font-size: 1.65em;
|
||||
}
|
||||
}
|
||||
&.icon-calendar:after {
|
||||
content: "\e605";
|
||||
}
|
||||
}
|
||||
|
||||
.bar .ui-symbol {
|
||||
@@ -52,7 +58,7 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.s-menu .invoke-menu,
|
||||
.s-menu-btn .invoke-menu,
|
||||
.icon.major .invoke-menu {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
|
||||
@@ -347,9 +347,10 @@
|
||||
/* This doesn't work on an element inside an element with absolute positioning that has height: auto */
|
||||
//position: relative;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
@include webkitProp(transform, translateY(-50%));
|
||||
//-webkit-transform: translateY(-50%);
|
||||
//-ms-transform: translateY(-50%);
|
||||
//transform: translateY(-50%);
|
||||
}
|
||||
|
||||
@mixin verticalCenterBlock($holderH, $itemH) {
|
||||
@@ -389,7 +390,7 @@
|
||||
}
|
||||
|
||||
@mixin test($c: #ffcc00, $a: 0.2) {
|
||||
background-color: rgba($c, $a);
|
||||
background-color: rgba($c, $a) !important;
|
||||
}
|
||||
|
||||
@mixin tmpBorder($c: #ffcc00, $a: 0.75) {
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
&.fixed {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
&.scrolling {
|
||||
overflow: auto;
|
||||
}
|
||||
.controls,
|
||||
label,
|
||||
.inline-block {
|
||||
|
||||
@@ -205,7 +205,7 @@ label.checkbox.custom {
|
||||
}
|
||||
}
|
||||
|
||||
.s-menu label.checkbox.custom {
|
||||
.s-menu-btn label.checkbox.custom {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@@ -295,49 +295,155 @@ label.checkbox.custom {
|
||||
|
||||
.slider {
|
||||
$knobH: 100%; //14px;
|
||||
$knobW: 12px;
|
||||
$slotH: 50%;
|
||||
.slot {
|
||||
// @include border-radius($basicCr * .75);
|
||||
@include sliderTrack();
|
||||
height: $slotH;
|
||||
//@include sliderTrack();
|
||||
width: auto;
|
||||
position: absolute;
|
||||
top: ($knobH - $slotH) / 2;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: auto;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
.knob {
|
||||
@include btnSubtle();
|
||||
@include controlGrippy(rgba(black, 0.3), vertical, 1px, solid);
|
||||
cursor: ew-resize;
|
||||
//@include btnSubtle();
|
||||
//@include controlGrippy(rgba(black, 0.3), vertical, 1px, solid);
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
background-color: $sliderColorKnob;
|
||||
&:hover {
|
||||
background-color: $sliderColorKnobHov;
|
||||
}
|
||||
position: absolute;
|
||||
height: $knobH;
|
||||
width: $knobW;
|
||||
width: $sliderKnobW;
|
||||
top: 0;
|
||||
auto: 0;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
&:before {
|
||||
top: 1px;
|
||||
bottom: 3px;
|
||||
left: ($knobW / 2) - 1;
|
||||
}
|
||||
|
||||
}
|
||||
.knob-l {
|
||||
@include border-left-radius($sliderKnobW);
|
||||
cursor: w-resize;
|
||||
}
|
||||
.knob-r {
|
||||
@include border-right-radius($sliderKnobW);
|
||||
cursor: e-resize;
|
||||
}
|
||||
.range {
|
||||
background: rgba($colorKey, 0.6);
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
background-color: $sliderColorRange;
|
||||
cursor: ew-resize;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: 0; //$tbOffset;
|
||||
right: auto;
|
||||
bottom: 0;
|
||||
left: auto;
|
||||
height: auto;
|
||||
width: auto;
|
||||
&:hover {
|
||||
background: rgba($colorKey, 0.7);
|
||||
background-color: $sliderColorRangeHov;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** DATETIME PICKER */
|
||||
.l-datetime-picker {
|
||||
$r1H: 15px;
|
||||
@include user-select(none);
|
||||
font-size: 0.8rem;
|
||||
padding: $interiorMarginLg !important;
|
||||
width: 230px;
|
||||
.l-month-year-pager {
|
||||
$pagerW: 20px;
|
||||
//@include test();
|
||||
//font-size: 0.8rem;
|
||||
height: $r1H;
|
||||
margin-bottom: $interiorMargin;
|
||||
position: relative;
|
||||
.pager,
|
||||
.val {
|
||||
//@include test(red);
|
||||
@extend .abs;
|
||||
}
|
||||
.pager {
|
||||
width: $pagerW;
|
||||
@extend .ui-symbol;
|
||||
&.prev {
|
||||
right: auto;
|
||||
&:before {
|
||||
content: "\3c";
|
||||
}
|
||||
}
|
||||
&.next {
|
||||
left: auto;
|
||||
text-align: right;
|
||||
&:before {
|
||||
content: "\3e";
|
||||
}
|
||||
}
|
||||
}
|
||||
.val {
|
||||
text-align: center;
|
||||
left: $pagerW + $interiorMargin;
|
||||
right: $pagerW + $interiorMargin;
|
||||
}
|
||||
}
|
||||
.l-calendar,
|
||||
.l-time-selects {
|
||||
border-top: 1px solid $colorInteriorBorder
|
||||
}
|
||||
.l-time-selects {
|
||||
line-height: $formInputH;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** CALENDAR */
|
||||
.l-calendar {
|
||||
$colorMuted: pushBack($colorMenuFg, 30%);
|
||||
ul.l-cal-row {
|
||||
@include display-flex;
|
||||
@include flex-flow(row nowrap);
|
||||
margin-top: 1px;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
li {
|
||||
@include flex(1 0);
|
||||
//@include test();
|
||||
margin-left: 1px;
|
||||
padding: $interiorMargin;
|
||||
text-align: center;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
&.l-header li {
|
||||
color: $colorMuted;
|
||||
}
|
||||
&.l-body li {
|
||||
@include trans-prop-nice(background-color, .25s);
|
||||
cursor: pointer;
|
||||
&.in-month {
|
||||
background-color: $colorCalCellInMonthBg;
|
||||
}
|
||||
.sub {
|
||||
color: $colorMuted;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
&.selected {
|
||||
background: $colorCalCellSelectedBg;
|
||||
color: $colorCalCellSelectedFg;
|
||||
.sub {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background-color: $colorCalCellHovBg;
|
||||
color: $colorCalCellHovFg;
|
||||
.sub {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/******************************************************** MENU BUTTONS */
|
||||
.s-menu {
|
||||
.s-menu-btn {
|
||||
// Formerly .btn-menu
|
||||
@extend .s-btn;
|
||||
span.l-click-area {
|
||||
@@ -62,186 +62,192 @@
|
||||
|
||||
/******************************************************** MENUS THEMSELVES */
|
||||
.menu-element {
|
||||
$bg: $colorMenuBg;
|
||||
$fg: $colorMenuFg;
|
||||
$ic: $colorMenuIc;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
.menu {
|
||||
@include border-radius($basicCr);
|
||||
@include containerSubtle($bg, $fg);
|
||||
@include boxShdw($shdwMenu);
|
||||
@include txtShdw($shdwMenuText);
|
||||
display: block; // set to block via jQuery
|
||||
padding: $interiorMarginSm 0;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
ul {
|
||||
@include menuUlReset();
|
||||
li {
|
||||
@include box-sizing(border-box);
|
||||
border-top: 1px solid lighten($bg, 20%);
|
||||
color: pullForward($bg, 60%);
|
||||
line-height: $menuLineH;
|
||||
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
&:first-child {
|
||||
border: none;
|
||||
}
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
.icon {
|
||||
color: $colorMenuHovIc;
|
||||
}
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu,
|
||||
.context-menu,
|
||||
.super-menu {
|
||||
pointer-events: auto;
|
||||
ul li {
|
||||
//padding-left: 25px;
|
||||
a {
|
||||
color: $fg;
|
||||
}
|
||||
.icon {
|
||||
color: $ic;
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin;
|
||||
}
|
||||
&:hover .icon {
|
||||
//color: lighten($ic, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.s-menu {
|
||||
@include border-radius($basicCr);
|
||||
@include containerSubtle($colorMenuBg, $colorMenuFg);
|
||||
@include boxShdw($shdwMenu);
|
||||
@include txtShdw($shdwMenuText);
|
||||
padding: $interiorMarginSm 0;
|
||||
}
|
||||
|
||||
.checkbox-menu {
|
||||
// Used in search dropdown in tree
|
||||
@extend .context-menu;
|
||||
ul li {
|
||||
padding-left: 50px;
|
||||
.checkbox {
|
||||
$d: 0.7rem;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: ($menuLineH - $d) / 1.5;
|
||||
em {
|
||||
height: $d;
|
||||
width: $d;
|
||||
&:before {
|
||||
font-size: 7px !important;// $d/2;
|
||||
height: $d;
|
||||
width: $d;
|
||||
line-height: $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
.type-icon {
|
||||
left: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.super-menu {
|
||||
$w: 500px;
|
||||
$h: $w - 20;
|
||||
$plw: 50%;
|
||||
$prw: 50%;
|
||||
display: block;
|
||||
width: $w;
|
||||
height: $h;
|
||||
.contents {
|
||||
@include absPosDefault($interiorMargin);
|
||||
}
|
||||
.pane {
|
||||
.menu {
|
||||
@extend .s-menu;
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
ul {
|
||||
@include menuUlReset();
|
||||
li {
|
||||
@include box-sizing(border-box);
|
||||
&.left {
|
||||
//@include test();
|
||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||
left: 0;
|
||||
padding-right: $interiorMargin;
|
||||
right: auto;
|
||||
width: $plw;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
ul {
|
||||
li {
|
||||
@include border-radius($controlCr);
|
||||
padding-left: 30px;
|
||||
border-top: none;
|
||||
}
|
||||
border-top: 1px solid lighten($colorMenuBg, 20%);
|
||||
color: pullForward($colorMenuBg, 60%);
|
||||
line-height: $menuLineH;
|
||||
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
&:first-child {
|
||||
border: none;
|
||||
}
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
.icon {
|
||||
color: $colorMenuHovIc;
|
||||
}
|
||||
}
|
||||
&.right {
|
||||
//@include test(red);
|
||||
left: auto;
|
||||
right: 0;
|
||||
padding: $interiorMargin * 5;
|
||||
width: $prw;
|
||||
.type-icon {
|
||||
left: $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
.menu-item-description {
|
||||
.desc-area {
|
||||
&.icon {
|
||||
$h: 150px;
|
||||
color: $colorCreateMenuLgIcon;
|
||||
position: relative;
|
||||
font-size: 8em;
|
||||
left: 0;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
margin-bottom: $interiorMargin * 5;
|
||||
text-align: center;
|
||||
}
|
||||
&.title {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
&.description {
|
||||
//color: lighten($bg, 30%);
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 0.8em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.context-menu {
|
||||
font-size: 0.80rem;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu-holder {
|
||||
pointer-events: none;
|
||||
.menu,
|
||||
.context-menu,
|
||||
.super-menu {
|
||||
pointer-events: auto;
|
||||
ul li {
|
||||
//padding-left: 25px;
|
||||
a {
|
||||
color: $colorMenuFg;
|
||||
}
|
||||
.icon {
|
||||
color: $colorMenuIc;
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin;
|
||||
}
|
||||
&:hover .icon {
|
||||
//color: lighten($colorMenuIc, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-menu {
|
||||
// Used in search dropdown in tree
|
||||
@extend .context-menu;
|
||||
ul li {
|
||||
padding-left: 50px;
|
||||
.checkbox {
|
||||
$d: 0.7rem;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: ($menuLineH - $d) / 1.5;
|
||||
em {
|
||||
height: $d;
|
||||
width: $d;
|
||||
&:before {
|
||||
font-size: 7px !important;// $d/2;
|
||||
height: $d;
|
||||
width: $d;
|
||||
line-height: $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
.type-icon {
|
||||
left: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.super-menu {
|
||||
$w: 500px;
|
||||
$h: $w - 20;
|
||||
$plw: 50%;
|
||||
$prw: 50%;
|
||||
display: block;
|
||||
width: $w;
|
||||
height: $h;
|
||||
.contents {
|
||||
@include absPosDefault($interiorMargin);
|
||||
}
|
||||
.pane {
|
||||
@include box-sizing(border-box);
|
||||
&.left {
|
||||
//@include test();
|
||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||
left: 0;
|
||||
padding-right: $interiorMargin;
|
||||
right: auto;
|
||||
width: $plw;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
ul {
|
||||
li {
|
||||
@include border-radius($controlCr);
|
||||
padding-left: 30px;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.right {
|
||||
//@include test(red);
|
||||
left: auto;
|
||||
right: 0;
|
||||
padding: $interiorMargin * 5;
|
||||
width: $prw;
|
||||
}
|
||||
}
|
||||
.menu-item-description {
|
||||
.desc-area {
|
||||
&.icon {
|
||||
$h: 150px;
|
||||
color: $colorCreateMenuLgIcon;
|
||||
position: relative;
|
||||
font-size: 8em;
|
||||
left: 0;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
margin-bottom: $interiorMargin * 5;
|
||||
text-align: center;
|
||||
}
|
||||
&.title {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
&.description {
|
||||
//color: lighten($colorMenuBg, 30%);
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 0.8em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.context-menu {
|
||||
font-size: 0.80rem;
|
||||
}
|
||||
|
||||
.context-menu-holder,
|
||||
.menu-holder {
|
||||
position: absolute;
|
||||
height: 200px;
|
||||
width: 170px;
|
||||
z-index: 70;
|
||||
.context-menu-wrapper {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
.context-menu {
|
||||
}
|
||||
}
|
||||
&.go-left .context-menu {
|
||||
&.go-left .context-menu,
|
||||
&.go-left .menu {
|
||||
right: 0;
|
||||
}
|
||||
&.go-up .context-menu {
|
||||
&.go-up .context-menu,
|
||||
&.go-up .menu {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu-holder {
|
||||
pointer-events: none;
|
||||
height: 200px;
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
.btn-bar.right .menu,
|
||||
.menus-to-left .menu {
|
||||
left: auto;
|
||||
|
||||
@@ -1,72 +1,155 @@
|
||||
.l-time-controller {
|
||||
$inputTxtW: 90px;
|
||||
$knobW: 9px;
|
||||
$r1H: 20px;
|
||||
$r2H: 30px;
|
||||
$r3H: 10px;
|
||||
@mixin toiLineHovEffects() {
|
||||
//@include pulse(.25s);
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: $timeControllerToiLineColorHov;
|
||||
}
|
||||
}
|
||||
|
||||
position: relative;
|
||||
margin: $interiorMarginLg 0;
|
||||
min-width: 400px;
|
||||
.l-time-controller-visible {
|
||||
|
||||
}
|
||||
|
||||
mct-include.l-time-controller {
|
||||
$minW: 500px;
|
||||
$knobHOffset: 0px;
|
||||
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
||||
$rangeValPad: $interiorMargin;
|
||||
$rangeValOffset: $sliderKnobW;
|
||||
//$knobCr: $sliderKnobW;
|
||||
$timeRangeSliderLROffset: 130px + $sliderKnobW + $rangeValOffset;
|
||||
$r1H: nth($ueTimeControlH,1);
|
||||
$r2H: nth($ueTimeControlH,2);
|
||||
$r3H: nth($ueTimeControlH,3);
|
||||
|
||||
@include absPosDefault();
|
||||
//@include test();
|
||||
display: block;
|
||||
top: auto;
|
||||
height: $r1H + $r2H + $r3H + ($interiorMargin * 2);
|
||||
min-width: $minW;
|
||||
font-size: 0.8rem;
|
||||
|
||||
.l-time-range-inputs-holder,
|
||||
.l-time-range-slider {
|
||||
font-size: 0.8em;
|
||||
//font-size: 0.8em;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder,
|
||||
.l-time-range-slider-holder,
|
||||
.l-time-range-ticks-holder
|
||||
{
|
||||
margin-bottom: $interiorMargin;
|
||||
position: relative;
|
||||
//@include test();
|
||||
@include absPosDefault(0, visible);
|
||||
@include box-sizing(border-box);
|
||||
top: auto;
|
||||
}
|
||||
.l-time-range-slider,
|
||||
.l-time-range-ticks {
|
||||
//@include test(red, 0.1);
|
||||
@include absPosDefault(0, visible);
|
||||
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
height: $r1H;
|
||||
}
|
||||
|
||||
.l-time-range-slider,
|
||||
.l-time-range-ticks {
|
||||
left: $inputTxtW; right: $inputTxtW;
|
||||
|
||||
//@include test(red);
|
||||
height: $r1H; bottom: $r2H + $r3H + ($interiorMarginSm * 2);
|
||||
padding-top: $interiorMargin;
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
.type-icon {
|
||||
font-size: 120%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.l-time-range-input,
|
||||
.l-time-range-inputs-elem {
|
||||
margin-right: $interiorMargin;
|
||||
.lbl {
|
||||
color: $colorPlotLabelFg;
|
||||
}
|
||||
.ui-symbol.icon {
|
||||
font-size: 11px;
|
||||
width: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-slider-holder {
|
||||
height: $r2H;
|
||||
//@include test(green);
|
||||
height: $r2H; bottom: $r3H + ($interiorMarginSm * 1);
|
||||
.range-holder {
|
||||
@include box-shadow(none);
|
||||
background: none;
|
||||
border: none;
|
||||
height: 75%;
|
||||
.range {
|
||||
.toi-line {
|
||||
$myC: $timeControllerToiLineColor;
|
||||
$myW: 8px;
|
||||
@include transform(translateX(50%));
|
||||
position: absolute;
|
||||
//@include test();
|
||||
top: 0; right: 0; bottom: 0px; left: auto;
|
||||
width: $myW;
|
||||
height: auto;
|
||||
z-index: 2;
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: $myC;
|
||||
content: "";
|
||||
position: absolute;
|
||||
}
|
||||
&:before {
|
||||
// Vert line
|
||||
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
||||
width: 2px;
|
||||
//top: 0; right: 3px; bottom: 0; left: 3px;
|
||||
}
|
||||
&:after {
|
||||
// Circle element
|
||||
@include border-radius($myW);
|
||||
@include transform(translateY(-50%));
|
||||
top: 50%; right: 0; bottom: auto; left: 0;
|
||||
width: auto;
|
||||
height: $myW;
|
||||
}
|
||||
}
|
||||
&:hover .toi-line {
|
||||
@include toiLineHovEffects;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:not(:active) {
|
||||
//@include test(#ff00cc);
|
||||
.knob,
|
||||
.range {
|
||||
@include transition-property(left, right);
|
||||
@include transition-duration(500ms);
|
||||
@include transition-timing-function(ease-in-out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-ticks-holder {
|
||||
height: $r3H;
|
||||
.l-time-range-ticks {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
border-top: 1px solid $colorTick;
|
||||
.tick {
|
||||
background-color: $colorInteriorBorder;
|
||||
background-color: $colorTick;
|
||||
border:none;
|
||||
height: 5px;
|
||||
width: 1px;
|
||||
margin-left: -1px;
|
||||
position: absolute;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
.l-time-range-tick-label {
|
||||
color: lighten($colorInteriorBorder, 20%);
|
||||
font-size: 0.7em;
|
||||
@include webkitProp(transform, translateX(-50%));
|
||||
color: $colorPlotLabelFg;
|
||||
display: inline-block;
|
||||
font-size: 0.9em;
|
||||
position: absolute;
|
||||
margin-left: -0.5 * $tickLblW;
|
||||
text-align: center;
|
||||
top: $r3H;
|
||||
width: $tickLblW;
|
||||
top: 8px;
|
||||
white-space: nowrap;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
@@ -74,31 +157,47 @@
|
||||
}
|
||||
|
||||
.knob {
|
||||
width: $knobW;
|
||||
z-index: 2;
|
||||
.range-value {
|
||||
$w: 75px;
|
||||
//@include test();
|
||||
//@include test($sliderColorRange);
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
padding: 0 $rangeValOffset;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -7px; // Label is 13px high
|
||||
height: $r2H;
|
||||
line-height: $r2H;
|
||||
white-space: nowrap;
|
||||
width: $w;
|
||||
}
|
||||
&:hover .range-value {
|
||||
color: $colorKey;
|
||||
color: $sliderColorKnobHov;
|
||||
}
|
||||
&.knob-l {
|
||||
margin-left: $knobW / -2;
|
||||
//@include border-bottom-left-radius($knobCr); // MOVED TO _CONTROLS.SCSS
|
||||
margin-left: $knobM;
|
||||
.range-value {
|
||||
text-align: right;
|
||||
right: $knobW + $interiorMargin;
|
||||
right: $rangeValOffset;
|
||||
}
|
||||
}
|
||||
&.knob-r {
|
||||
margin-right: $knobW / -2;
|
||||
//@include border-bottom-right-radius($knobCr);
|
||||
margin-right: $knobM;
|
||||
.range-value {
|
||||
left: $knobW + $interiorMargin;
|
||||
left: $rangeValOffset;
|
||||
}
|
||||
&:hover + .range-holder .range .toi-line {
|
||||
@include toiLineHovEffects;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//.slot.range-holder {
|
||||
// background-color: $sliderColorRangeHolder;
|
||||
//}
|
||||
|
||||
.s-time-range-val {
|
||||
//@include test();
|
||||
@include border-radius($controlCr);
|
||||
background-color: $colorInputBg;
|
||||
padding: 1px 1px 0 $interiorMargin;
|
||||
}
|
||||
@@ -19,39 +19,44 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@mixin complexFieldHolder($myW) {
|
||||
width: $myW + $interiorMargin;
|
||||
input[type="text"] {
|
||||
width: $myW;
|
||||
}
|
||||
}
|
||||
|
||||
.complex.datetime {
|
||||
span {
|
||||
display: inline-block;
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
.field-hints,
|
||||
.fields {
|
||||
}
|
||||
|
||||
|
||||
.field-hints {
|
||||
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
.fields {
|
||||
margin-top: $interiorMarginSm 0;
|
||||
padding: $interiorMarginSm 0;
|
||||
}
|
||||
|
||||
.date {
|
||||
$myW: 80px;
|
||||
width: $myW + $interiorMargin;
|
||||
input {
|
||||
width: $myW;
|
||||
}
|
||||
|
||||
@include complexFieldHolder(80px);
|
||||
}
|
||||
|
||||
.time.md {
|
||||
@include complexFieldHolder(60px);
|
||||
}
|
||||
|
||||
.time.sm {
|
||||
$myW: 40px;
|
||||
width: $myW + $interiorMargin;
|
||||
input {
|
||||
width: $myW;
|
||||
}
|
||||
@include complexFieldHolder(40px);
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,13 @@
|
||||
*****************************************************************************/
|
||||
.select {
|
||||
@include btnSubtle($colorSelectBg);
|
||||
margin: 0 0 2px 2px; // Needed to avoid dropshadow from being clipped by parent containers
|
||||
@if $shdwBtns != none {
|
||||
margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
|
||||
}
|
||||
padding: 0 $interiorMargin;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
line-height: $formInputH;
|
||||
select {
|
||||
@include appearance(none);
|
||||
@include box-sizing(border-box);
|
||||
@@ -40,11 +43,8 @@
|
||||
}
|
||||
&:after {
|
||||
@include contextArrow();
|
||||
pointer-events: none;
|
||||
color: rgba($colorSelectFg, percentToDecimal($contrastInvokeMenuPercent));
|
||||
//content:"v";
|
||||
//display: block;
|
||||
//font-family: 'symbolsfont';
|
||||
//pointer-events: none;
|
||||
position: absolute;
|
||||
right: $interiorMargin; top: 0;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ table {
|
||||
thead, .thead {
|
||||
border-bottom: 1px solid $colorTabHeaderBorder;
|
||||
}
|
||||
|
||||
&:not(.fixed-header) tr th {
|
||||
background-color: $colorTabHeaderBg;
|
||||
}
|
||||
|
||||
tbody, .tbody {
|
||||
display: table-row-group;
|
||||
tr, .tr {
|
||||
@@ -64,7 +69,6 @@ table {
|
||||
display: table-cell;
|
||||
}
|
||||
th, .th {
|
||||
background-color: $colorTabHeaderBg;
|
||||
border-left: 1px solid $colorTabHeaderBorder;
|
||||
color: $colorTabHeaderFg;
|
||||
padding: $tabularTdPadLR $tabularTdPadLR;
|
||||
@@ -143,7 +147,7 @@ table {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: $tabularHeaderH;
|
||||
background: rgba(#fff, 0.15);
|
||||
background-color: $colorTabHeaderBg;
|
||||
}
|
||||
}
|
||||
tbody, .tbody {
|
||||
|
||||
@@ -89,7 +89,7 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
.gl-plot-label,
|
||||
.l-plot-label {
|
||||
// @include test(yellow);
|
||||
color: lighten($colorBodyFg, 20%);
|
||||
color: $colorPlotLabelFg;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
// text-transform: uppercase;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
&.frame-template {
|
||||
.s-btn,
|
||||
.s-menu {
|
||||
.s-menu-btn {
|
||||
height: $ohH;
|
||||
line-height: $ohH;
|
||||
padding: 0 $interiorMargin;
|
||||
@@ -56,7 +56,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.s-menu:after {
|
||||
.s-menu-btn:after {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,21 +30,21 @@
|
||||
}
|
||||
|
||||
.holder-all {
|
||||
$myM: 0; // $interiorMarginSm;
|
||||
top: $myM;
|
||||
right: $myM;
|
||||
bottom: $myM;
|
||||
left: $myM;
|
||||
$myM: 0; // $interiorMarginSm;
|
||||
top: $myM;
|
||||
right: $myM;
|
||||
bottom: $myM;
|
||||
left: $myM;
|
||||
}
|
||||
|
||||
.browse-area,
|
||||
.edit-area,
|
||||
.editor {
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.editor {
|
||||
@include border-radius($basicCr * 1.5);
|
||||
@include border-radius($basicCr * 1.5);
|
||||
}
|
||||
|
||||
.contents {
|
||||
@@ -68,8 +68,8 @@
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
&.abs {
|
||||
text-wrap: none;
|
||||
white-space: nowrap;
|
||||
text-wrap: none;
|
||||
white-space: nowrap;
|
||||
&.left,
|
||||
.left {
|
||||
width: 45%;
|
||||
@@ -95,51 +95,51 @@
|
||||
}
|
||||
|
||||
.user-environ {
|
||||
.browse-area,
|
||||
.edit-area,
|
||||
.editor {
|
||||
top: $bodyMargin + $ueTopBarH + ($interiorMargin);
|
||||
right: $bodyMargin;
|
||||
bottom: $ueFooterH + $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
}
|
||||
.browse-area,
|
||||
.edit-area,
|
||||
.editor {
|
||||
top: $bodyMargin + $ueTopBarH + ($interiorMargin);
|
||||
right: $bodyMargin;
|
||||
bottom: $ueFooterH + $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
}
|
||||
|
||||
.browse-area,
|
||||
.edit-area {
|
||||
> .contents {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
.browse-area,
|
||||
.edit-area {
|
||||
> .contents {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-area {
|
||||
$tbH: $btnToolbarH + $interiorMargin;
|
||||
top: $bodyMargin + $ueTopBarEditH + ($interiorMargin);
|
||||
.tool-bar {
|
||||
bottom: auto;
|
||||
height: $tbH;
|
||||
line-height: $btnToolbarH;
|
||||
}
|
||||
.work-area {
|
||||
top: $tbH + $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
.edit-area {
|
||||
$tbH: $btnToolbarH + $interiorMargin;
|
||||
top: $bodyMargin + $ueTopBarEditH + ($interiorMargin);
|
||||
.tool-bar {
|
||||
bottom: auto;
|
||||
height: $tbH;
|
||||
line-height: $btnToolbarH;
|
||||
}
|
||||
.work-area {
|
||||
top: $tbH + $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
|
||||
.ue-bottom-bar {
|
||||
.ue-bottom-bar {
|
||||
//@include absPosDefault($bodyMargin);
|
||||
@include absPosDefault(0);// New status bar design
|
||||
top: auto;
|
||||
height: $ueFooterH;
|
||||
.status-holder {
|
||||
//right: $ueAppLogoW + $bodyMargin; New status bar design
|
||||
z-index: 1;
|
||||
}
|
||||
.app-logo {
|
||||
left: auto;
|
||||
width: $ueAppLogoW;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
@include absPosDefault(0); // New status bar design
|
||||
top: auto;
|
||||
height: $ueFooterH;
|
||||
.status-holder {
|
||||
//right: $ueAppLogoW + $bodyMargin; New status bar design
|
||||
z-index: 1;
|
||||
}
|
||||
.app-logo {
|
||||
left: auto;
|
||||
width: $ueAppLogoW;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cols {
|
||||
@@ -225,89 +225,89 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.pane {
|
||||
position: absolute;
|
||||
&.treeview.left {
|
||||
.create-btn-holder {
|
||||
bottom: auto; top: 0;
|
||||
height: $ueTopBarH;
|
||||
.wrapper.menu-element {
|
||||
position: absolute;
|
||||
bottom: $interiorMargin;
|
||||
}
|
||||
}
|
||||
.search-holder {
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
}
|
||||
.tree-holder {
|
||||
overflow: auto;
|
||||
top: $ueTopBarH + $interiorMarginLg + $treeSearchInputBarH + $interiorMargin;
|
||||
}
|
||||
.create-btn-holder {
|
||||
bottom: auto;
|
||||
top: 0;
|
||||
height: $ueTopBarH;
|
||||
.wrapper.menu-element {
|
||||
position: absolute;
|
||||
bottom: $interiorMargin;
|
||||
}
|
||||
}
|
||||
.search-holder {
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
}
|
||||
.tree-holder {
|
||||
overflow: auto;
|
||||
top: $ueTopBarH + $interiorMarginLg + $treeSearchInputBarH + $interiorMargin;
|
||||
}
|
||||
}
|
||||
&.items {
|
||||
.object-browse-bar {
|
||||
.left.abs,
|
||||
.right.abs {
|
||||
top: auto;
|
||||
}
|
||||
//.left.abs {
|
||||
// @include tmpBorder(green);
|
||||
//}
|
||||
//.right.abs {
|
||||
// @include tmpBorder(red);
|
||||
//}
|
||||
}
|
||||
.object-holder {
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
.left.abs,
|
||||
.right.abs {
|
||||
top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
.object-holder {
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.split-layout {
|
||||
&.horizontal {
|
||||
// Slides up and down
|
||||
>.pane {
|
||||
// @include test();
|
||||
margin-top: $interiorMargin;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.vertical {
|
||||
// Slides left and right
|
||||
>.pane {
|
||||
// @include test();
|
||||
margin-left: $interiorMargin;
|
||||
>.holder {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
.holder {
|
||||
right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.horizontal {
|
||||
// Slides up and down
|
||||
> .pane {
|
||||
// @include test();
|
||||
margin-top: $interiorMargin;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.vertical {
|
||||
// Slides left and right
|
||||
> .pane {
|
||||
// @include test();
|
||||
margin-left: $interiorMargin;
|
||||
> .holder {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
.holder {
|
||||
right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.object-holder {
|
||||
overflow: hidden; // Contained objects need to handle their own overflow now
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
> ng-include {
|
||||
@include absPosDefault(0, auto);
|
||||
}
|
||||
&.l-controls-visible {
|
||||
&.l-time-controller-visible {
|
||||
bottom: nth($ueTimeControlH,1) + nth($ueTimeControlH,2) +nth($ueTimeControlH,3) + ($interiorMargin * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.object-browse-bar .s-btn,
|
||||
.top-bar .buttons-main .s-btn,
|
||||
.top-bar .s-menu,
|
||||
.top-bar .s-menu-btn,
|
||||
.tool-bar .s-btn,
|
||||
.tool-bar .s-menu {
|
||||
$h: $btnToolbarH;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
vertical-align: top;
|
||||
.tool-bar .s-menu-btn {
|
||||
$h: $btnToolbarH;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.object-browse-bar,
|
||||
@@ -318,33 +318,29 @@
|
||||
}
|
||||
|
||||
.object-browse-bar {
|
||||
//@include test(blue);
|
||||
@include absPosDefault(0, visible);
|
||||
@include box-sizing(border-box);
|
||||
height: $ueTopBarH;
|
||||
line-height: $ueTopBarH;
|
||||
white-space: nowrap;
|
||||
//@include test(blue);
|
||||
@include absPosDefault(0, visible);
|
||||
@include box-sizing(border-box);
|
||||
height: $ueTopBarH;
|
||||
line-height: $ueTopBarH;
|
||||
white-space: nowrap;
|
||||
|
||||
.left {
|
||||
padding-right: $interiorMarginLg * 2;
|
||||
.l-back {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
padding-right: $interiorMarginLg * 2;
|
||||
.l-back {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-flex {
|
||||
@include webkitVal('display', 'flex');
|
||||
@include webkitProp('flex-flow', 'row nowrap');
|
||||
.left {
|
||||
//@include test(red);
|
||||
@include webkitProp(flex, '1 1 0');
|
||||
padding-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
|
||||
.vscroll {
|
||||
overflow-y: auto;
|
||||
}
|
||||
@include webkitVal('display', 'flex');
|
||||
@include webkitProp('flex-flow', 'row nowrap');
|
||||
.left {
|
||||
//@include test(red);
|
||||
@include webkitProp(flex, '1 1 0');
|
||||
padding-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT Web includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<div ng-controller="DateTimePickerController" class="l-datetime-picker s-datetime-picker s-menu">
|
||||
<div class="holder">
|
||||
<div class="l-month-year-pager">
|
||||
<a class="pager prev" ng-click="changeMonth(-1)"></a>
|
||||
<span class="val">{{month}} {{year}}</span>
|
||||
<a class="pager next" ng-click="changeMonth(1)"></a>
|
||||
</div>
|
||||
<div class="l-calendar">
|
||||
<ul class="l-cal-row l-header">
|
||||
<li ng-repeat="day in ['Su','Mo','Tu','We','Th','Fr','Sa']">{{day}}</li>
|
||||
</ul>
|
||||
<ul class="l-cal-row l-body" ng-repeat="row in table">
|
||||
<li ng-repeat="cell in row"
|
||||
ng-click="select(cell)"
|
||||
ng-class='{ "in-month": isInCurrentMonth(cell), selected: isSelected(cell) }'>
|
||||
<div class="prime">{{cell.day}}</div>
|
||||
<div class="sub">{{cell.dayOfYear}}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-time-selects complex datetime"
|
||||
ng-show="options">
|
||||
<div class="field-hints">
|
||||
<span class="hint time md"
|
||||
ng-repeat="key in ['hours', 'minutes', 'seconds']"
|
||||
ng-if="options[key]">
|
||||
{{nameFor(key)}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="field control time md"
|
||||
ng-repeat="key in ['hours', 'minutes', 'seconds']"
|
||||
ng-if="options[key]">
|
||||
<div class='form-control select'>
|
||||
<select size="1"
|
||||
ng-model="time[key]"
|
||||
ng-options="i for i in optionsFor(key)">
|
||||
</select>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<span ng-controller="ViewSwitcherController">
|
||||
<div
|
||||
class="view-switcher menu-element s-menu"
|
||||
class="view-switcher menu-element s-menu-btn"
|
||||
ng-if="view.length > 1"
|
||||
ng-controller="ClickAwayController as toggle"
|
||||
>
|
||||
|
||||
@@ -1,55 +1,88 @@
|
||||
<!--
|
||||
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.
|
||||
|
||||
NOTES
|
||||
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.
|
||||
|
||||
Ticks:
|
||||
The thinking is to divide whatever the current time span is by 5,
|
||||
and assign values accordingly to 5 statically-positioned ticks. So the tick x-position is a static percentage
|
||||
of the total width available, and the labels change dynamically. This is consistent
|
||||
with our current approach to the time axis of plots.
|
||||
I'm keeping the number of ticks low so that when the view portal gets narrow,
|
||||
the tick labels won't collide with each other. For extra credit, add/remove ticks as the user resizes the view area.
|
||||
Note: this eval needs to be based on the whatever is containing the
|
||||
time-controller component, not the whole browser window.
|
||||
|
||||
Range indicator and slider knobs:
|
||||
The left and right properties used in .slider .range-holder and the .knobs are
|
||||
CSS offsets from the left and right of their respective containers. You
|
||||
may want or need to calculate those positions as pure offsets from the start datetime
|
||||
(or left, as it were) and set them as left properties. No problem if so, but
|
||||
we'll need to tweak the CSS tiny bit to get the center of the knobs to line up
|
||||
properly on the range left and right bounds.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT Web includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<div ng-init="
|
||||
notes = 'Temporarily using an array to populate ticks so I can see what I\'m doing';
|
||||
ticks = [
|
||||
'00:00',
|
||||
'00:30',
|
||||
'01:00',
|
||||
'01:30',
|
||||
'02:00'
|
||||
];
|
||||
"></div>
|
||||
|
||||
<div class="l-time-controller">
|
||||
<!-- MINE -->
|
||||
<div ng-controller="TimeRangeController">
|
||||
<div class="l-time-range-inputs-holder">
|
||||
Start: <input type="date" />
|
||||
End: <input type="date" />
|
||||
<span class="l-time-range-inputs-elem ui-symbol type-icon">C</span>
|
||||
<span class="l-time-range-input" ng-controller="ToggleController as t1">
|
||||
<!--<span class="lbl">Start</span>-->
|
||||
<span class="s-btn time-range-start" ng-click="t1.toggle()">
|
||||
<span class="val">{{startOuterText}}</span>
|
||||
<a class="ui-symbol icon icon-calendar"></a>
|
||||
<mct-popup ng-if="t1.isActive()">
|
||||
<div mct-click-elsewhere="t1.setState(false)">
|
||||
<mct-control key="'datetime-picker'"
|
||||
ng-model="ngModel.outer"
|
||||
field="'start'"
|
||||
options="{ hours: true }">
|
||||
</mct-control>
|
||||
</div>
|
||||
</mct-popup>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="l-time-range-inputs-elem lbl">to</span>
|
||||
|
||||
<span class="l-time-range-input" ng-controller="ToggleController as t2">
|
||||
<!--<span class="lbl">End</span>-->
|
||||
<span class="s-btn l-time-range-input" ng-click="t2.toggle()">
|
||||
<span class="val">{{endOuterText}}</span>
|
||||
<a class="ui-symbol icon icon-calendar"></a>
|
||||
<mct-popup ng-if="t2.isActive()">
|
||||
<div mct-click-elsewhere="t2.setState(false)">
|
||||
<mct-control key="'datetime-picker'"
|
||||
ng-model="ngModel.outer"
|
||||
field="'end'"
|
||||
options="{ hours: true }">
|
||||
</mct-control>
|
||||
</div>
|
||||
</mct-popup>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="l-time-range-slider-holder">
|
||||
<div class="l-time-range-slider">
|
||||
<div class="slider">
|
||||
<div class="slider"
|
||||
mct-resize="spanWidth = bounds.width">
|
||||
<div class="knob knob-l"
|
||||
mct-drag-down="startLeftDrag()"
|
||||
mct-drag="leftDrag(delta[0])"
|
||||
ng-style="{ left: startInnerPct }">
|
||||
<div class="range-value">{{startInnerText}}</div>
|
||||
</div>
|
||||
<div class="knob knob-r"
|
||||
mct-drag-down="startRightDrag()"
|
||||
mct-drag="rightDrag(delta[0])"
|
||||
ng-style="{ right: endInnerPct }">
|
||||
<div class="range-value">{{endInnerText}}</div>
|
||||
</div>
|
||||
<div class="slot range-holder">
|
||||
<div class="range" style="left: 0%; right: 30%;"></div>
|
||||
</div>
|
||||
<div class="knob knob-l" style="left: 0%;">
|
||||
<div class="range-value">05/22 14:46</div>
|
||||
</div>
|
||||
<div class="knob knob-r" style="right: 30%;">
|
||||
<div class="range-value">07/22 01:21</div>
|
||||
<div class="range"
|
||||
mct-drag-down="startMiddleDrag()"
|
||||
mct-drag="middleDrag(delta[0])"
|
||||
ng-style="{ left: startInnerPct, right: endInnerPct}">
|
||||
<div class="toi-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,7 +92,7 @@ ticks = [
|
||||
<div class="l-time-range-ticks">
|
||||
<div
|
||||
ng-repeat="tick in ticks"
|
||||
ng-style="{ left: $index * 25 + '%' }"
|
||||
ng-style="{ left: $index * (100 / (ticks.length - 1)) + '%' }"
|
||||
class="tick tick-x"
|
||||
>
|
||||
<span class="l-time-range-tick-label">{{tick}}</span>
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
[ 'moment' ],
|
||||
function (moment) {
|
||||
'use strict';
|
||||
|
||||
var TIME_NAMES = {
|
||||
'hours': "Hour",
|
||||
'minutes': "Minute",
|
||||
'seconds': "Second"
|
||||
},
|
||||
MONTHS = moment.months(),
|
||||
TIME_OPTIONS = (function makeRanges() {
|
||||
var arr = [];
|
||||
while (arr.length < 60) {
|
||||
arr.push(arr.length);
|
||||
}
|
||||
return {
|
||||
hours: arr.slice(0, 24),
|
||||
minutes: arr,
|
||||
seconds: arr
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* Controller to support the date-time picker.
|
||||
*
|
||||
* Adds/uses the following properties in scope:
|
||||
* * `year`: Year being displayed in picker
|
||||
* * `month`: Month being displayed
|
||||
* * `table`: Table being displayed; array of arrays of
|
||||
* * `day`: Day of month
|
||||
* * `dayOfYear`: Day of year
|
||||
* * `month`: Month associated with the day
|
||||
* * `year`: Year associated with the day.
|
||||
* * `date`: Date chosen
|
||||
* * `year`: Year selected
|
||||
* * `month`: Month selected (0-indexed)
|
||||
* * `day`: Day of month selected
|
||||
* * `time`: Chosen time (hours/minutes/seconds)
|
||||
* * `hours`: Hours chosen
|
||||
* * `minutes`: Minutes chosen
|
||||
* * `seconds`: Seconds chosen
|
||||
*
|
||||
* Months are zero-indexed, day-of-months are one-indexed.
|
||||
*/
|
||||
function DateTimePickerController($scope, now) {
|
||||
var year,
|
||||
month, // For picker state, not model state
|
||||
interacted = false;
|
||||
|
||||
function generateTable() {
|
||||
var m = moment.utc({ year: year, month: month }).day(0),
|
||||
table = [],
|
||||
row,
|
||||
col;
|
||||
|
||||
for (row = 0; row < 6; row += 1) {
|
||||
table.push([]);
|
||||
for (col = 0; col < 7; col += 1) {
|
||||
table[row].push({
|
||||
year: m.year(),
|
||||
month: m.month(),
|
||||
day: m.date(),
|
||||
dayOfYear: m.dayOfYear()
|
||||
});
|
||||
m.add(1, 'days'); // Next day!
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
function updateScopeForMonth() {
|
||||
$scope.month = MONTHS[month];
|
||||
$scope.year = year;
|
||||
$scope.table = generateTable();
|
||||
}
|
||||
|
||||
function updateFromModel(ngModel) {
|
||||
var m;
|
||||
|
||||
m = moment.utc(ngModel);
|
||||
|
||||
$scope.date = {
|
||||
year: m.year(),
|
||||
month: m.month(),
|
||||
day: m.date()
|
||||
};
|
||||
$scope.time = {
|
||||
hours: m.hour(),
|
||||
minutes: m.minute(),
|
||||
seconds: m.second()
|
||||
};
|
||||
|
||||
//window.alert($scope.date.day + " " + ngModel);
|
||||
|
||||
// Zoom to that date in the picker, but
|
||||
// only if the user hasn't interacted with it yet.
|
||||
if (!interacted) {
|
||||
year = m.year();
|
||||
month = m.month();
|
||||
updateScopeForMonth();
|
||||
}
|
||||
}
|
||||
|
||||
function updateFromView() {
|
||||
var m = moment.utc({
|
||||
year: $scope.date.year,
|
||||
month: $scope.date.month,
|
||||
day: $scope.date.day,
|
||||
hour: $scope.time.hours,
|
||||
minute: $scope.time.minutes,
|
||||
second: $scope.time.seconds
|
||||
});
|
||||
$scope.ngModel[$scope.field] = m.valueOf();
|
||||
}
|
||||
|
||||
$scope.isInCurrentMonth = function (cell) {
|
||||
return cell.month === month;
|
||||
};
|
||||
|
||||
$scope.isSelected = function (cell) {
|
||||
var date = $scope.date || {};
|
||||
return cell.day === date.day &&
|
||||
cell.month === date.month &&
|
||||
cell.year === date.year;
|
||||
};
|
||||
|
||||
$scope.select = function (cell) {
|
||||
$scope.date = $scope.date || {};
|
||||
$scope.date.month = cell.month;
|
||||
$scope.date.year = cell.year;
|
||||
$scope.date.day = cell.day;
|
||||
updateFromView();
|
||||
};
|
||||
|
||||
$scope.dateEquals = function (d1, d2) {
|
||||
return d1.year === d2.year &&
|
||||
d1.month === d2.month &&
|
||||
d1.day === d2.day;
|
||||
};
|
||||
|
||||
$scope.changeMonth = function (delta) {
|
||||
month += delta;
|
||||
if (month > 11) {
|
||||
month = 0;
|
||||
year += 1;
|
||||
}
|
||||
if (month < 0) {
|
||||
month = 11;
|
||||
year -= 1;
|
||||
}
|
||||
interacted = true;
|
||||
updateScopeForMonth();
|
||||
};
|
||||
|
||||
$scope.nameFor = function (key) {
|
||||
return TIME_NAMES[key];
|
||||
};
|
||||
|
||||
$scope.optionsFor = function (key) {
|
||||
return TIME_OPTIONS[key];
|
||||
};
|
||||
|
||||
updateScopeForMonth();
|
||||
|
||||
// Ensure some useful default
|
||||
$scope.ngModel[$scope.field] =
|
||||
$scope.ngModel[$scope.field] === undefined ?
|
||||
now() : $scope.ngModel[$scope.field];
|
||||
|
||||
$scope.$watch('ngModel[field]', updateFromModel);
|
||||
$scope.$watchCollection('date', updateFromView);
|
||||
$scope.$watchCollection('time', updateFromView);
|
||||
}
|
||||
|
||||
return DateTimePickerController;
|
||||
}
|
||||
);
|
||||
239
platform/commonUI/general/src/controllers/TimeRangeController.js
Normal file
239
platform/commonUI/general/src/controllers/TimeRangeController.js
Normal file
@@ -0,0 +1,239 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['moment'],
|
||||
function (moment) {
|
||||
"use strict";
|
||||
|
||||
var
|
||||
DATE_FORMAT = "YYYY-MM-DD HH:mm:ss",
|
||||
TICK_SPACING_PX = 150;
|
||||
|
||||
/**
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function TimeConductorController($scope, now) {
|
||||
var tickCount = 2,
|
||||
innerMinimumSpan = 1000, // 1 second
|
||||
outerMinimumSpan = 1000 * 60 * 60, // 1 hour
|
||||
initialDragValue;
|
||||
|
||||
function formatTimestamp(ts) {
|
||||
return moment.utc(ts).format(DATE_FORMAT);
|
||||
}
|
||||
|
||||
// From 0.0-1.0 to "0%"-"1%"
|
||||
function toPercent(p) {
|
||||
return (100 * p) + "%";
|
||||
}
|
||||
|
||||
function updateTicks() {
|
||||
var i, p, ts, start, end, span;
|
||||
end = $scope.ngModel.outer.end;
|
||||
start = $scope.ngModel.outer.start;
|
||||
span = end - start;
|
||||
$scope.ticks = [];
|
||||
for (i = 0; i < tickCount; i += 1) {
|
||||
p = i / (tickCount - 1);
|
||||
ts = p * span + start;
|
||||
$scope.ticks.push(formatTimestamp(ts));
|
||||
}
|
||||
}
|
||||
|
||||
function updateSpanWidth(w) {
|
||||
tickCount = Math.max(Math.floor(w / TICK_SPACING_PX), 2);
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
function updateViewForInnerSpanFromModel(ngModel) {
|
||||
var span = ngModel.outer.end - ngModel.outer.start;
|
||||
|
||||
// Expose readable dates for the knobs
|
||||
$scope.startInnerText = formatTimestamp(ngModel.inner.start);
|
||||
$scope.endInnerText = formatTimestamp(ngModel.inner.end);
|
||||
|
||||
// And positions for the knobs
|
||||
$scope.startInnerPct =
|
||||
toPercent((ngModel.inner.start - ngModel.outer.start) / span);
|
||||
$scope.endInnerPct =
|
||||
toPercent((ngModel.outer.end - ngModel.inner.end) / span);
|
||||
}
|
||||
|
||||
function defaultBounds() {
|
||||
var t = now();
|
||||
return {
|
||||
start: t - 24 * 3600 * 1000, // One day
|
||||
end: t
|
||||
};
|
||||
}
|
||||
|
||||
function copyBounds(bounds) {
|
||||
return { start: bounds.start, end: bounds.end };
|
||||
}
|
||||
|
||||
function updateViewFromModel(ngModel) {
|
||||
var t = now();
|
||||
|
||||
ngModel = ngModel || {};
|
||||
ngModel.outer = ngModel.outer || defaultBounds();
|
||||
ngModel.inner = ngModel.inner || copyBounds(ngModel.outer);
|
||||
|
||||
// First, dates for the date pickers for outer bounds
|
||||
$scope.startOuterDate = new Date(ngModel.outer.start);
|
||||
$scope.endOuterDate = new Date(ngModel.outer.end);
|
||||
|
||||
// Then various updates for the inner span
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
|
||||
// Stick it back is scope (in case we just set defaults)
|
||||
$scope.ngModel = ngModel;
|
||||
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
function startLeftDrag() {
|
||||
initialDragValue = $scope.ngModel.inner.start;
|
||||
}
|
||||
|
||||
function startRightDrag() {
|
||||
initialDragValue = $scope.ngModel.inner.end;
|
||||
}
|
||||
|
||||
function startMiddleDrag() {
|
||||
initialDragValue = {
|
||||
start: $scope.ngModel.inner.start,
|
||||
end: $scope.ngModel.inner.end
|
||||
};
|
||||
}
|
||||
|
||||
function toMillis(pixels) {
|
||||
var span = $scope.ngModel.outer.end - $scope.ngModel.outer.start;
|
||||
return (pixels / $scope.spanWidth) * span;
|
||||
}
|
||||
|
||||
function clamp(value, low, high) {
|
||||
return Math.max(low, Math.min(high, value));
|
||||
}
|
||||
|
||||
function leftDrag(pixels) {
|
||||
var delta = toMillis(pixels);
|
||||
$scope.ngModel.inner.start = clamp(
|
||||
initialDragValue + delta,
|
||||
$scope.ngModel.outer.start,
|
||||
$scope.ngModel.inner.end - innerMinimumSpan
|
||||
);
|
||||
updateViewFromModel($scope.ngModel);
|
||||
}
|
||||
|
||||
function rightDrag(pixels) {
|
||||
var delta = toMillis(pixels);
|
||||
$scope.ngModel.inner.end = clamp(
|
||||
initialDragValue + delta,
|
||||
$scope.ngModel.inner.start + innerMinimumSpan,
|
||||
$scope.ngModel.outer.end
|
||||
);
|
||||
updateViewFromModel($scope.ngModel);
|
||||
}
|
||||
|
||||
function middleDrag(pixels) {
|
||||
var delta = toMillis(pixels),
|
||||
edge = delta < 0 ? 'start' : 'end',
|
||||
opposite = delta < 0 ? 'end' : 'start';
|
||||
|
||||
// Adjust the position of the edge in the direction of drag
|
||||
$scope.ngModel.inner[edge] = clamp(
|
||||
initialDragValue[edge] + delta,
|
||||
$scope.ngModel.outer.start,
|
||||
$scope.ngModel.outer.end
|
||||
);
|
||||
// Adjust opposite knob to maintain span
|
||||
$scope.ngModel.inner[opposite] = $scope.ngModel.inner[edge] +
|
||||
initialDragValue[opposite] - initialDragValue[edge];
|
||||
|
||||
updateViewFromModel($scope.ngModel);
|
||||
}
|
||||
|
||||
function updateOuterStart(t) {
|
||||
var ngModel = $scope.ngModel;
|
||||
|
||||
ngModel.outer.end = Math.max(
|
||||
ngModel.outer.start + outerMinimumSpan,
|
||||
ngModel.outer.end
|
||||
);
|
||||
|
||||
ngModel.inner.start =
|
||||
Math.max(ngModel.outer.start, ngModel.inner.start);
|
||||
ngModel.inner.end = Math.max(
|
||||
ngModel.inner.start + innerMinimumSpan,
|
||||
ngModel.inner.end
|
||||
);
|
||||
|
||||
$scope.startOuterText = formatTimestamp(t);
|
||||
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
}
|
||||
|
||||
function updateOuterEnd(t) {
|
||||
var ngModel = $scope.ngModel;
|
||||
|
||||
ngModel.outer.start = Math.min(
|
||||
ngModel.outer.end - outerMinimumSpan,
|
||||
ngModel.outer.start
|
||||
);
|
||||
|
||||
ngModel.inner.end =
|
||||
Math.min(ngModel.outer.end, ngModel.inner.end);
|
||||
ngModel.inner.start = Math.min(
|
||||
ngModel.inner.end - innerMinimumSpan,
|
||||
ngModel.inner.start
|
||||
);
|
||||
|
||||
$scope.endOuterText = formatTimestamp(t);
|
||||
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
}
|
||||
|
||||
$scope.startLeftDrag = startLeftDrag;
|
||||
$scope.startRightDrag = startRightDrag;
|
||||
$scope.startMiddleDrag = startMiddleDrag;
|
||||
$scope.leftDrag = leftDrag;
|
||||
$scope.rightDrag = rightDrag;
|
||||
$scope.middleDrag = middleDrag;
|
||||
|
||||
$scope.state = false;
|
||||
$scope.ticks = [];
|
||||
|
||||
// Initialize scope to defaults
|
||||
updateViewFromModel($scope.ngModel);
|
||||
|
||||
$scope.$watchCollection("ngModel", updateViewFromModel);
|
||||
$scope.$watch("spanWidth", updateSpanWidth);
|
||||
$scope.$watch("ngModel.outer.start", updateOuterStart);
|
||||
$scope.$watch("ngModel.outer.end", updateOuterEnd);
|
||||
}
|
||||
|
||||
return TimeConductorController;
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,77 @@
|
||||
/*****************************************************************************
|
||||
* 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 `mct-click-elsewhere` directive will evaluate its
|
||||
* associated expression whenever a `mousedown` occurs anywhere
|
||||
* outside of the element that has the `mct-click-elsewhere`
|
||||
* directive attached. This is useful for dismissing popups
|
||||
* and the like.
|
||||
*/
|
||||
function MCTClickElsewhere($document) {
|
||||
|
||||
// Link; install event handlers.
|
||||
function link(scope, element, attrs) {
|
||||
// Keep a reference to the body, to attach/detach
|
||||
// mouse event handlers; mousedown and mouseup cannot
|
||||
// only be attached to the element being linked, as the
|
||||
// mouse may leave this element during the drag.
|
||||
var body = $document.find('body');
|
||||
|
||||
function clickBody(event) {
|
||||
var x = event.clientX,
|
||||
y = event.clientY,
|
||||
rect = element[0].getBoundingClientRect(),
|
||||
xMin = rect.left,
|
||||
xMax = xMin + rect.width,
|
||||
yMin = rect.top,
|
||||
yMax = yMin + rect.height;
|
||||
|
||||
if (x < xMin || x > xMax || y < yMin || y > yMax) {
|
||||
scope.$eval(attrs.mctClickElsewhere);
|
||||
}
|
||||
}
|
||||
|
||||
body.on("mousedown", clickBody);
|
||||
scope.$on("$destroy", function () {
|
||||
body.off("mousedown", clickBody);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// mct-drag only makes sense as an attribute
|
||||
restrict: "A",
|
||||
// Link function, to install event handlers
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTClickElsewhere;
|
||||
}
|
||||
);
|
||||
|
||||
73
platform/commonUI/general/src/directives/MCTPopup.js
Normal file
73
platform/commonUI/general/src/directives/MCTPopup.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************
|
||||
* 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';
|
||||
|
||||
var TEMPLATE = "<div></div>";
|
||||
|
||||
/**
|
||||
* The `mct-popup` directive may be used to display elements
|
||||
* which "pop up" over other parts of the page. Typically, this is
|
||||
* done in conjunction with an `ng-if` to control the visibility
|
||||
* of the popup.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* <mct-popup ng-if="someExpr">
|
||||
* <span>These are the contents of the popup!</span>
|
||||
* </mct-popup>
|
||||
*
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/general
|
||||
* @param $compile Angular's $compile service
|
||||
* @param {platform/commonUI/general.PopupService} popupService
|
||||
*/
|
||||
function MCTPopup($compile, popupService) {
|
||||
function link(scope, element, attrs, ctrl, transclude) {
|
||||
var div = $compile(TEMPLATE)(scope),
|
||||
rect = element.parent()[0].getBoundingClientRect(),
|
||||
position = [ rect.left, rect.top ],
|
||||
popup = popupService.display(div, position);
|
||||
|
||||
transclude(function (clone) {
|
||||
div.append(clone);
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function () {
|
||||
popup.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "E",
|
||||
transclude: true,
|
||||
link: link,
|
||||
scope: {}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTPopup;
|
||||
}
|
||||
);
|
||||
@@ -58,6 +58,7 @@ define(
|
||||
// Link; start listening for changes to an element's size
|
||||
function link(scope, element, attrs) {
|
||||
var lastBounds,
|
||||
linking = true,
|
||||
active = true;
|
||||
|
||||
// Determine how long to wait before the next update
|
||||
@@ -74,7 +75,9 @@ define(
|
||||
lastBounds.width !== bounds.width ||
|
||||
lastBounds.height !== bounds.height) {
|
||||
scope.$eval(attrs.mctResize, { bounds: bounds });
|
||||
scope.$apply(); // Trigger a digest
|
||||
if (!linking) { // Avoid apply-in-a-digest
|
||||
scope.$apply();
|
||||
}
|
||||
lastBounds = bounds;
|
||||
}
|
||||
}
|
||||
@@ -101,6 +104,9 @@ define(
|
||||
|
||||
// Handle the initial callback
|
||||
onInterval();
|
||||
|
||||
// Trigger scope.$apply on subsequent changes
|
||||
linking = false;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -49,22 +49,17 @@ define(
|
||||
var expr = attrs[attribute],
|
||||
parsed = $parse(expr);
|
||||
|
||||
// Set the element's scroll to match the scope's state
|
||||
function updateElement(value) {
|
||||
element[0][property] = value;
|
||||
}
|
||||
|
||||
// Handle event; assign to scroll state to scope
|
||||
function updateScope() {
|
||||
parsed.assign(scope, element[0][property]);
|
||||
scope.$apply(expr);
|
||||
}
|
||||
|
||||
// Set the element's scroll to match the scope's state
|
||||
function updateElement(value) {
|
||||
element[0][property] = value;
|
||||
// Some values may be out of range for the scroll bar,
|
||||
// so publish the real scroll value back into scope.
|
||||
if (element[0][property] !== value) {
|
||||
parsed.assign(scope, element[0][property]);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize state in scope
|
||||
parsed.assign(scope, element[0][property]);
|
||||
|
||||
|
||||
89
platform/commonUI/general/src/services/Popup.js
Normal file
89
platform/commonUI/general/src/services/Popup.js
Normal 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";
|
||||
|
||||
/**
|
||||
* A popup is an element that has been displayed at a particular
|
||||
* location within the page.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/general
|
||||
* @param element the jqLite-wrapped element
|
||||
* @param {object} styles an object containing key-value pairs
|
||||
* of styles used to position the element.
|
||||
*/
|
||||
function Popup(element, styles) {
|
||||
this.styles = styles;
|
||||
this.element = element;
|
||||
|
||||
element.css(styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop showing this popup.
|
||||
*/
|
||||
Popup.prototype.dismiss = function () {
|
||||
this.element.remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears to the
|
||||
* left of its original location.
|
||||
* @returns {boolean} true if the popup goes left
|
||||
*/
|
||||
Popup.prototype.goesLeft = function () {
|
||||
return !this.styles.left;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears to the
|
||||
* right of its original location.
|
||||
* @returns {boolean} true if the popup goes right
|
||||
*/
|
||||
Popup.prototype.goesRight = function () {
|
||||
return !this.styles.right;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears above
|
||||
* its original location.
|
||||
* @returns {boolean} true if the popup goes up
|
||||
*/
|
||||
Popup.prototype.goesUp = function () {
|
||||
return !this.styles.top;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears below
|
||||
* its original location.
|
||||
* @returns {boolean} true if the popup goes down
|
||||
*/
|
||||
Popup.prototype.goesDown = function () {
|
||||
return !this.styles.bottom;
|
||||
};
|
||||
|
||||
return Popup;
|
||||
}
|
||||
);
|
||||
127
platform/commonUI/general/src/services/PopupService.js
Normal file
127
platform/commonUI/general/src/services/PopupService.js
Normal file
@@ -0,0 +1,127 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./Popup'],
|
||||
function (Popup) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Displays popup elements at specific positions within the document.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function PopupService($document, $window) {
|
||||
this.$document = $document;
|
||||
this.$window = $window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options controlling how the popup is displaed.
|
||||
*
|
||||
* @typedef PopupOptions
|
||||
* @memberof platform/commonUI/general
|
||||
* @property {number} [offsetX] the horizontal distance, in pixels,
|
||||
* to offset the element in whichever direction it is
|
||||
* displayed. Defaults to 0.
|
||||
* @property {number} [offsetY] the vertical distance, in pixels,
|
||||
* to offset the element in whichever direction it is
|
||||
* displayed. Defaults to 0.
|
||||
* @property {number} [marginX] the horizontal position, in pixels,
|
||||
* after which to prefer to display the element to the left.
|
||||
* If negative, this is relative to the right edge of the
|
||||
* page. Defaults to half the window's width.
|
||||
* @property {number} [marginY] the vertical position, in pixels,
|
||||
* after which to prefer to display the element upward.
|
||||
* If negative, this is relative to the right edge of the
|
||||
* page. Defaults to half the window's height.
|
||||
* @property {string} [leftClass] class to apply when shifting to the left
|
||||
* @property {string} [rightClass] class to apply when shifting to the right
|
||||
* @property {string} [upClass] class to apply when shifting upward
|
||||
* @property {string} [downClass] class to apply when shifting downward
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display a popup at a particular location. The location chosen will
|
||||
* be the corner of the element; the element will be positioned either
|
||||
* to the left or the right of this point depending on available
|
||||
* horizontal space, and will similarly be shifted upward or downward
|
||||
* depending on available vertical space.
|
||||
*
|
||||
* @param element the jqLite-wrapped DOM element to pop up
|
||||
* @param {number[]} position x,y position of the element, in
|
||||
* pixel coordinates. Negative values are interpreted as
|
||||
* relative to the right or bottom of the window.
|
||||
* @param {PopupOptions} [options] additional options to control
|
||||
* positioning of the popup
|
||||
* @returns {platform/commonUI/general.Popup} the popup
|
||||
*/
|
||||
PopupService.prototype.display = function (element, position, options) {
|
||||
var $document = this.$document,
|
||||
$window = this.$window,
|
||||
body = $document.find('body'),
|
||||
winDim = [ $window.innerWidth, $window.innerHeight ],
|
||||
styles = { position: 'absolute' },
|
||||
margin,
|
||||
offset,
|
||||
bubble;
|
||||
|
||||
function adjustNegatives(value, index) {
|
||||
return value < 0 ? (value + winDim[index]) : value;
|
||||
}
|
||||
|
||||
// Defaults
|
||||
options = options || {};
|
||||
offset = [
|
||||
options.offsetX !== undefined ? options.offsetX : 0,
|
||||
options.offsetY !== undefined ? options.offsetY : 0
|
||||
];
|
||||
margin = [ options.marginX, options.marginY ].map(function (m, i) {
|
||||
return m === undefined ? (winDim[i] / 2) : m;
|
||||
}).map(adjustNegatives);
|
||||
|
||||
position = position.map(adjustNegatives);
|
||||
|
||||
if (position[0] > margin[0]) {
|
||||
styles.right = (winDim[0] - position[0] + offset[0]) + 'px';
|
||||
} else {
|
||||
styles.left = (position[0] + offset[0]) + 'px';
|
||||
}
|
||||
|
||||
if (position[1] > margin[1]) {
|
||||
styles.bottom = (winDim[1] - position[1] + offset[1]) + 'px';
|
||||
} else {
|
||||
styles.top = (position[1] + offset[1]) + 'px';
|
||||
}
|
||||
|
||||
// Add the menu to the body
|
||||
body.append(element);
|
||||
|
||||
// Return a function to dismiss the bubble
|
||||
return new Popup(element, styles);
|
||||
};
|
||||
|
||||
return PopupService;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*****************************************************************************
|
||||
* 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/controllers/DateTimePickerController"],
|
||||
function (DateTimePickerController) {
|
||||
"use strict";
|
||||
|
||||
describe("The DateTimePickerController", function () {
|
||||
var mockScope,
|
||||
mockNow,
|
||||
controller;
|
||||
|
||||
function fireWatch(expr, value) {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
[ "$apply", "$watch", "$watchCollection" ]
|
||||
);
|
||||
mockScope.ngModel = {};
|
||||
mockScope.field = "testField";
|
||||
mockNow = jasmine.createSpy('now');
|
||||
controller = new DateTimePickerController(mockScope, mockNow);
|
||||
});
|
||||
|
||||
it("watches the model that was passed in", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"ngModel[field]",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,173 @@
|
||||
/*****************************************************************************
|
||||
* 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/controllers/TimeRangeController"],
|
||||
function (TimeRangeController) {
|
||||
"use strict";
|
||||
|
||||
var SEC = 1000,
|
||||
MIN = 60 * SEC,
|
||||
HOUR = 60 * MIN,
|
||||
DAY = 24 * HOUR;
|
||||
|
||||
describe("The TimeRangeController", function () {
|
||||
var mockScope,
|
||||
mockNow,
|
||||
controller;
|
||||
|
||||
function fireWatch(expr, value) {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fireWatchCollection(expr, value) {
|
||||
mockScope.$watchCollection.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
[ "$apply", "$watch", "$watchCollection" ]
|
||||
);
|
||||
mockNow = jasmine.createSpy('now');
|
||||
controller = new TimeRangeController(mockScope, mockNow);
|
||||
});
|
||||
|
||||
it("watches the model that was passed in", function () {
|
||||
expect(mockScope.$watchCollection)
|
||||
.toHaveBeenCalledWith("ngModel", jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe("when dragged", function () {
|
||||
beforeEach(function () {
|
||||
mockScope.ngModel = {
|
||||
outer: {
|
||||
start: DAY * 1000,
|
||||
end: DAY * 1001
|
||||
},
|
||||
inner: {
|
||||
start: DAY * 1000 + HOUR * 3,
|
||||
end: DAY * 1001 - HOUR * 3
|
||||
}
|
||||
};
|
||||
mockScope.spanWidth = 1000;
|
||||
fireWatch("spanWidth", mockScope.spanWidth);
|
||||
fireWatchCollection("ngModel", mockScope.ngModel);
|
||||
});
|
||||
|
||||
it("updates the start time for left drags", function () {
|
||||
mockScope.startLeftDrag();
|
||||
mockScope.leftDrag(250);
|
||||
expect(mockScope.ngModel.inner.start)
|
||||
.toEqual(DAY * 1000 + HOUR * 9);
|
||||
});
|
||||
|
||||
it("updates the end time for right drags", function () {
|
||||
mockScope.startRightDrag();
|
||||
mockScope.rightDrag(-250);
|
||||
expect(mockScope.ngModel.inner.end)
|
||||
.toEqual(DAY * 1000 + HOUR * 15);
|
||||
});
|
||||
|
||||
it("updates both start and end for middle drags", function () {
|
||||
mockScope.startMiddleDrag();
|
||||
mockScope.middleDrag(-125);
|
||||
expect(mockScope.ngModel.inner).toEqual({
|
||||
start: DAY * 1000,
|
||||
end: DAY * 1000 + HOUR * 18
|
||||
});
|
||||
mockScope.middleDrag(250);
|
||||
expect(mockScope.ngModel.inner).toEqual({
|
||||
start: DAY * 1000 + HOUR * 6,
|
||||
end: DAY * 1001
|
||||
});
|
||||
});
|
||||
|
||||
it("enforces a minimum inner span", function () {
|
||||
mockScope.startRightDrag();
|
||||
mockScope.rightDrag(-9999999);
|
||||
expect(mockScope.ngModel.inner.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.inner.start);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when outer bounds are changed", function () {
|
||||
beforeEach(function () {
|
||||
mockScope.ngModel = {
|
||||
outer: {
|
||||
start: DAY * 1000,
|
||||
end: DAY * 1001
|
||||
},
|
||||
inner: {
|
||||
start: DAY * 1000 + HOUR * 3,
|
||||
end: DAY * 1001 - HOUR * 3
|
||||
}
|
||||
};
|
||||
mockScope.spanWidth = 1000;
|
||||
fireWatch("spanWidth", mockScope.spanWidth);
|
||||
fireWatchCollection("ngModel", mockScope.ngModel);
|
||||
});
|
||||
|
||||
it("enforces a minimum outer span", function () {
|
||||
mockScope.ngModel.outer.end =
|
||||
mockScope.ngModel.outer.start - DAY * 100;
|
||||
fireWatch(
|
||||
"ngModel.outer.end",
|
||||
mockScope.ngModel.outer.end
|
||||
);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.outer.start);
|
||||
|
||||
mockScope.ngModel.outer.start =
|
||||
mockScope.ngModel.outer.end + DAY * 100;
|
||||
fireWatch(
|
||||
"ngModel.outer.start",
|
||||
mockScope.ngModel.outer.start
|
||||
);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.outer.start);
|
||||
});
|
||||
|
||||
it("enforces a minimum inner span when outer span changes", function () {
|
||||
mockScope.ngModel.outer.end =
|
||||
mockScope.ngModel.outer.start - DAY * 100;
|
||||
fireWatch(
|
||||
"ngModel.outer.end",
|
||||
mockScope.ngModel.outer.end
|
||||
);
|
||||
expect(mockScope.ngModel.inner.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.inner.start);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,84 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/directives/MCTClickElsewhere"],
|
||||
function (MCTClickElsewhere) {
|
||||
"use strict";
|
||||
|
||||
var JQLITE_METHODS = [ "on", "off", "find", "parent" ];
|
||||
|
||||
describe("The mct-click-elsewhere directive", function () {
|
||||
var mockDocument,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockBody,
|
||||
mockParentEl,
|
||||
testRect,
|
||||
mctClickElsewhere;
|
||||
|
||||
function testEvent(x, y) {
|
||||
return {
|
||||
pageX: x,
|
||||
pageY: y,
|
||||
preventDefault: jasmine.createSpy("preventDefault")
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockDocument =
|
||||
jasmine.createSpyObj("$document", JQLITE_METHODS);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", [ "$eval", "$apply", "$on" ]);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", JQLITE_METHODS);
|
||||
mockBody =
|
||||
jasmine.createSpyObj("body", JQLITE_METHODS);
|
||||
mockParentEl =
|
||||
jasmine.createSpyObj("parent", ["getBoundingClientRect"]);
|
||||
|
||||
testAttrs = {
|
||||
mctClickElsewhere: "some Angular expression"
|
||||
};
|
||||
testRect = {
|
||||
left: 20,
|
||||
top: 42,
|
||||
width: 60,
|
||||
height: 75
|
||||
};
|
||||
|
||||
mockDocument.find.andReturn(mockBody);
|
||||
|
||||
mctClickElsewhere = new MCTClickElsewhere(mockDocument);
|
||||
mctClickElsewhere.link(mockScope, mockElement, testAttrs);
|
||||
});
|
||||
|
||||
it("is valid as an attribute", function () {
|
||||
expect(mctClickElsewhere.restrict).toEqual("A");
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
136
platform/commonUI/general/test/directives/MCTPopupSpec.js
Normal file
136
platform/commonUI/general/test/directives/MCTPopupSpec.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/directives/MCTPopup"],
|
||||
function (MCTPopup) {
|
||||
"use strict";
|
||||
|
||||
var JQLITE_METHODS = [ "on", "off", "find", "parent", "css", "append" ];
|
||||
|
||||
describe("The mct-popup directive", function () {
|
||||
var mockCompile,
|
||||
mockPopupService,
|
||||
mockPopup,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockBody,
|
||||
mockTransclude,
|
||||
mockParentEl,
|
||||
mockNewElement,
|
||||
testRect,
|
||||
mctPopup;
|
||||
|
||||
function testEvent(x, y) {
|
||||
return {
|
||||
pageX: x,
|
||||
pageY: y,
|
||||
preventDefault: jasmine.createSpy("preventDefault")
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockCompile =
|
||||
jasmine.createSpy("$compile");
|
||||
mockPopupService =
|
||||
jasmine.createSpyObj("popupService", ["display"]);
|
||||
mockPopup =
|
||||
jasmine.createSpyObj("popup", ["dismiss"]);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", [ "$eval", "$apply", "$on" ]);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", JQLITE_METHODS);
|
||||
mockBody =
|
||||
jasmine.createSpyObj("body", JQLITE_METHODS);
|
||||
mockTransclude =
|
||||
jasmine.createSpy("transclude");
|
||||
mockParentEl =
|
||||
jasmine.createSpyObj("parent", ["getBoundingClientRect"]);
|
||||
mockNewElement =
|
||||
jasmine.createSpyObj("newElement", JQLITE_METHODS);
|
||||
|
||||
testAttrs = {
|
||||
mctClickElsewhere: "some Angular expression"
|
||||
};
|
||||
testRect = {
|
||||
left: 20,
|
||||
top: 42,
|
||||
width: 60,
|
||||
height: 75
|
||||
};
|
||||
|
||||
mockCompile.andCallFake(function () {
|
||||
var mockFn = jasmine.createSpy();
|
||||
mockFn.andReturn(mockNewElement);
|
||||
return mockFn;
|
||||
});
|
||||
mockElement.parent.andReturn([mockParentEl]);
|
||||
mockParentEl.getBoundingClientRect.andReturn(testRect);
|
||||
mockPopupService.display.andReturn(mockPopup);
|
||||
|
||||
mctPopup = new MCTPopup(mockCompile, mockPopupService);
|
||||
|
||||
mctPopup.link(
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
null,
|
||||
mockTransclude
|
||||
);
|
||||
});
|
||||
|
||||
it("is valid as an element", function () {
|
||||
expect(mctPopup.restrict).toEqual("E");
|
||||
});
|
||||
|
||||
describe("creates an element which", function () {
|
||||
it("displays as a popup", function () {
|
||||
expect(mockPopupService.display).toHaveBeenCalledWith(
|
||||
mockNewElement,
|
||||
[ testRect.left, testRect.top ]
|
||||
);
|
||||
});
|
||||
|
||||
it("displays transcluded content", function () {
|
||||
var mockClone =
|
||||
jasmine.createSpyObj('clone', JQLITE_METHODS);
|
||||
mockTransclude.mostRecentCall.args[0](mockClone);
|
||||
expect(mockNewElement.append)
|
||||
.toHaveBeenCalledWith(mockClone);
|
||||
});
|
||||
|
||||
it("is removed when its containing scope is destroyed", function () {
|
||||
expect(mockPopup.dismiss).not.toHaveBeenCalled();
|
||||
mockScope.$on.calls.forEach(function (call) {
|
||||
if (call.args[0] === '$destroy') {
|
||||
call.args[1]();
|
||||
}
|
||||
});
|
||||
expect(mockPopup.dismiss).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
98
platform/commonUI/general/test/services/PopupServiceSpec.js
Normal file
98
platform/commonUI/general/test/services/PopupServiceSpec.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/*****************************************************************************
|
||||
* 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/PopupService"],
|
||||
function (PopupService) {
|
||||
'use strict';
|
||||
|
||||
describe("PopupService", function () {
|
||||
var mockDocument,
|
||||
testWindow,
|
||||
mockBody,
|
||||
mockElement,
|
||||
popupService;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDocument = jasmine.createSpyObj('$document', [ 'find' ]);
|
||||
testWindow = { innerWidth: 1000, innerHeight: 800 };
|
||||
mockBody = jasmine.createSpyObj('body', [ 'append' ]);
|
||||
mockElement = jasmine.createSpyObj('element', [
|
||||
'css',
|
||||
'remove'
|
||||
]);
|
||||
|
||||
mockDocument.find.andCallFake(function (query) {
|
||||
return query === 'body' && mockBody;
|
||||
});
|
||||
|
||||
popupService = new PopupService(mockDocument, testWindow);
|
||||
});
|
||||
|
||||
it("adds elements to the body of the document", function () {
|
||||
popupService.display(mockElement, [ 0, 0 ]);
|
||||
expect(mockBody.append).toHaveBeenCalledWith(mockElement);
|
||||
});
|
||||
|
||||
describe("when positioned in appropriate quadrants", function () {
|
||||
it("orients elements relative to the top-left", function () {
|
||||
popupService.display(mockElement, [ 25, 50 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
left: '25px',
|
||||
top: '50px'
|
||||
});
|
||||
});
|
||||
|
||||
it("orients elements relative to the top-right", function () {
|
||||
popupService.display(mockElement, [ 800, 50 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
right: '200px',
|
||||
top: '50px'
|
||||
});
|
||||
});
|
||||
|
||||
it("orients elements relative to the bottom-right", function () {
|
||||
popupService.display(mockElement, [ 800, 650 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
right: '200px',
|
||||
bottom: '150px'
|
||||
});
|
||||
});
|
||||
|
||||
it("orients elements relative to the bottom-left", function () {
|
||||
popupService.display(mockElement, [ 120, 650 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
left: '120px',
|
||||
bottom: '150px'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
74
platform/commonUI/general/test/services/PopupSpec.js
Normal file
74
platform/commonUI/general/test/services/PopupSpec.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
* 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/Popup"],
|
||||
function (Popup) {
|
||||
'use strict';
|
||||
|
||||
describe("Popup", function () {
|
||||
var mockElement,
|
||||
testStyles,
|
||||
popup;
|
||||
|
||||
beforeEach(function () {
|
||||
mockElement =
|
||||
jasmine.createSpyObj('element', [ 'css', 'remove' ]);
|
||||
testStyles = { left: '12px', top: '14px' };
|
||||
popup = new Popup(mockElement, testStyles);
|
||||
});
|
||||
|
||||
it("applies CSS styles when instantiated", function () {
|
||||
expect(mockElement.css)
|
||||
.toHaveBeenCalledWith(testStyles);
|
||||
});
|
||||
|
||||
it("reports the orientation of the popup", function () {
|
||||
var otherStyles = {
|
||||
right: '12px',
|
||||
bottom: '14px'
|
||||
},
|
||||
otherPopup = new Popup(mockElement, otherStyles);
|
||||
|
||||
expect(popup.goesLeft()).toBeFalsy();
|
||||
expect(popup.goesRight()).toBeTruthy();
|
||||
expect(popup.goesUp()).toBeFalsy();
|
||||
expect(popup.goesDown()).toBeTruthy();
|
||||
|
||||
expect(otherPopup.goesLeft()).toBeTruthy();
|
||||
expect(otherPopup.goesRight()).toBeFalsy();
|
||||
expect(otherPopup.goesUp()).toBeTruthy();
|
||||
expect(otherPopup.goesDown()).toBeFalsy();
|
||||
});
|
||||
|
||||
it("removes elements when dismissed", function () {
|
||||
expect(mockElement.remove).not.toHaveBeenCalled();
|
||||
popup.dismiss();
|
||||
expect(mockElement.remove).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
@@ -3,16 +3,22 @@
|
||||
"controllers/BottomBarController",
|
||||
"controllers/ClickAwayController",
|
||||
"controllers/ContextMenuController",
|
||||
"controllers/DateTimePickerController",
|
||||
"controllers/GetterSetterController",
|
||||
"controllers/SelectorController",
|
||||
"controllers/SplitPaneController",
|
||||
"controllers/TimeRangeController",
|
||||
"controllers/ToggleController",
|
||||
"controllers/TreeNodeController",
|
||||
"controllers/ViewSwitcherController",
|
||||
"directives/MCTClickElsewhere",
|
||||
"directives/MCTContainer",
|
||||
"directives/MCTDrag",
|
||||
"directives/MCTPopup",
|
||||
"directives/MCTResize",
|
||||
"directives/MCTScroll",
|
||||
"services/Popup",
|
||||
"services/PopupService",
|
||||
"services/UrlService",
|
||||
"StyleSheetLoader"
|
||||
]
|
||||
|
||||
@@ -45,13 +45,12 @@
|
||||
"implementation": "services/InfoService.js",
|
||||
"depends": [
|
||||
"$compile",
|
||||
"$document",
|
||||
"$window",
|
||||
"$rootScope",
|
||||
"popupService",
|
||||
"agentService"
|
||||
]
|
||||
}
|
||||
],
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"key": "INFO_HOVER_DELAY",
|
||||
@@ -66,4 +65,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,19 @@ define({
|
||||
BUBBLE_TEMPLATE: "<mct-container key=\"bubble\" " +
|
||||
"bubble-title=\"{{bubbleTitle}}\" " +
|
||||
"bubble-layout=\"{{bubbleLayout}}\" " +
|
||||
"class=\"bubble-container\">" +
|
||||
"<mct-include key=\"bubbleTemplate\" ng-model=\"bubbleModel\">" +
|
||||
"class=\"bubble-container\">" +
|
||||
"<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
|
||||
// Options and classes for bubble
|
||||
BUBBLE_OPTIONS: {
|
||||
offsetX: 0,
|
||||
offsetY: -26
|
||||
},
|
||||
BUBBLE_MOBILE_POSITION: [ 0, -25 ],
|
||||
// Max width and margins allowed for bubbles;
|
||||
// defined in /platform/commonUI/general/res/sass/_constants.scss
|
||||
BUBBLE_MARGIN_LR: 10,
|
||||
BUBBLE_MAX_WIDTH: 300
|
||||
});
|
||||
|
||||
@@ -27,18 +27,18 @@ define(
|
||||
"use strict";
|
||||
|
||||
var BUBBLE_TEMPLATE = InfoConstants.BUBBLE_TEMPLATE,
|
||||
OFFSET = InfoConstants.BUBBLE_OFFSET;
|
||||
MOBILE_POSITION = InfoConstants.BUBBLE_MOBILE_POSITION,
|
||||
OPTIONS = InfoConstants.BUBBLE_OPTIONS;
|
||||
|
||||
/**
|
||||
* Displays informative content ("info bubbles") for the user.
|
||||
* @memberof platform/commonUI/inspect
|
||||
* @constructor
|
||||
*/
|
||||
function InfoService($compile, $document, $window, $rootScope, agentService) {
|
||||
function InfoService($compile, $rootScope, popupService, agentService) {
|
||||
this.$compile = $compile;
|
||||
this.$document = $document;
|
||||
this.$window = $window;
|
||||
this.$rootScope = $rootScope;
|
||||
this.popupService = popupService;
|
||||
this.agentService = agentService;
|
||||
}
|
||||
|
||||
@@ -55,53 +55,47 @@ define(
|
||||
*/
|
||||
InfoService.prototype.display = function (templateKey, title, content, position) {
|
||||
var $compile = this.$compile,
|
||||
$document = this.$document,
|
||||
$window = this.$window,
|
||||
$rootScope = this.$rootScope,
|
||||
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),
|
||||
span = $compile('<span></span>')(scope),
|
||||
bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR +
|
||||
InfoConstants.BUBBLE_MAX_WIDTH,
|
||||
options,
|
||||
popup,
|
||||
bubble;
|
||||
|
||||
|
||||
options = Object.create(OPTIONS);
|
||||
options.marginX = -bubbleSpaceLR;
|
||||
|
||||
// On a phone, bubble takes up more screen real estate,
|
||||
// so position it differently (toward the bottom)
|
||||
if (this.agentService.isPhone(navigator.userAgent)) {
|
||||
position = MOBILE_POSITION;
|
||||
options = {};
|
||||
}
|
||||
|
||||
popup = this.popupService.display(span, position, options);
|
||||
|
||||
// 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;
|
||||
// Style the bubble according to how it was positioned
|
||||
scope.bubbleLayout = [
|
||||
popup.goesUp() ? 'arw-btm' : 'arw-top',
|
||||
popup.goesLeft() ? 'arw-right' : 'arw-left'
|
||||
].join(' ');
|
||||
scope.bubbleLayout = 'arw-top arw-left';
|
||||
|
||||
// Create the context menu
|
||||
// Create the info bubble, now that we know how to
|
||||
// point the arrow...
|
||||
bubble = $compile(BUBBLE_TEMPLATE)(scope);
|
||||
span.append(bubble);
|
||||
|
||||
// Position the bubble
|
||||
bubble.css('position', 'absolute');
|
||||
if (this.agentService.isPhone(navigator.userAgent)) {
|
||||
bubble.css('right', '0px');
|
||||
bubble.css('left', '0px');
|
||||
bubble.css('top', 'auto');
|
||||
bubble.css('bottom', '25px');
|
||||
} else {
|
||||
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 a function to dismiss the info bubble
|
||||
return function dismiss() {
|
||||
popup.dismiss();
|
||||
scope.$destroy();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -28,117 +28,85 @@ define(
|
||||
|
||||
describe("The info service", function () {
|
||||
var mockCompile,
|
||||
mockDocument,
|
||||
testWindow,
|
||||
mockRootScope,
|
||||
mockPopupService,
|
||||
mockAgentService,
|
||||
mockCompiledTemplate,
|
||||
testScope,
|
||||
mockBody,
|
||||
mockElement,
|
||||
mockScope,
|
||||
mockElements,
|
||||
mockPopup,
|
||||
service;
|
||||
|
||||
beforeEach(function () {
|
||||
mockCompile = jasmine.createSpy('$compile');
|
||||
mockDocument = jasmine.createSpyObj('$document', ['find']);
|
||||
testWindow = { innerWidth: 1000, innerHeight: 100 };
|
||||
mockRootScope = jasmine.createSpyObj('$rootScope', ['$new']);
|
||||
mockAgentService = jasmine.createSpyObj('agentService', ['isMobile', 'isPhone']);
|
||||
mockCompiledTemplate = jasmine.createSpy('template');
|
||||
testScope = {};
|
||||
mockBody = jasmine.createSpyObj('body', ['append']);
|
||||
mockElement = jasmine.createSpyObj('element', ['css', 'remove']);
|
||||
mockPopupService = jasmine.createSpyObj(
|
||||
'popupService',
|
||||
['display']
|
||||
);
|
||||
mockPopup = jasmine.createSpyObj('popup', [
|
||||
'dismiss',
|
||||
'goesLeft',
|
||||
'goesRight',
|
||||
'goesUp',
|
||||
'goesDown'
|
||||
]);
|
||||
|
||||
mockDocument.find.andCallFake(function (tag) {
|
||||
return tag === 'body' ? mockBody : undefined;
|
||||
mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
|
||||
mockElements = [];
|
||||
|
||||
mockPopupService.display.andReturn(mockPopup);
|
||||
mockCompile.andCallFake(function () {
|
||||
var mockCompiledTemplate = jasmine.createSpy('template'),
|
||||
mockElement = jasmine.createSpyObj('element', [
|
||||
'css',
|
||||
'remove',
|
||||
'append'
|
||||
]);
|
||||
mockCompiledTemplate.andReturn(mockElement);
|
||||
mockElements.push(mockElement);
|
||||
return mockCompiledTemplate;
|
||||
});
|
||||
mockCompile.andReturn(mockCompiledTemplate);
|
||||
mockCompiledTemplate.andReturn(mockElement);
|
||||
mockRootScope.$new.andReturn(testScope);
|
||||
mockRootScope.$new.andReturn(mockScope);
|
||||
|
||||
service = new InfoService(
|
||||
mockCompile,
|
||||
mockDocument,
|
||||
testWindow,
|
||||
mockRootScope,
|
||||
mockPopupService,
|
||||
mockAgentService
|
||||
);
|
||||
});
|
||||
|
||||
it("creates elements and appends them to the body to display", function () {
|
||||
service.display('', '', {}, [0, 0]);
|
||||
expect(mockBody.append).toHaveBeenCalledWith(mockElement);
|
||||
it("creates elements and displays them as popups", function () {
|
||||
service.display('', '', {}, [123, 456]);
|
||||
expect(mockPopupService.display).toHaveBeenCalledWith(
|
||||
mockElements[0],
|
||||
[ 123, 456 ],
|
||||
jasmine.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
it("provides a function to remove displayed info bubbles", function () {
|
||||
var fn = service.display('', '', {}, [0, 0]);
|
||||
expect(mockElement.remove).not.toHaveBeenCalled();
|
||||
expect(mockPopup.dismiss).not.toHaveBeenCalled();
|
||||
fn();
|
||||
expect(mockElement.remove).toHaveBeenCalled();
|
||||
expect(mockPopup.dismiss).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'
|
||||
);
|
||||
});
|
||||
|
||||
it("when on phone device, positioning is always on bottom", function () {
|
||||
mockAgentService.isPhone.andReturn(true);
|
||||
service = new InfoService(
|
||||
mockCompile,
|
||||
mockDocument,
|
||||
testWindow,
|
||||
mockRootScope,
|
||||
mockAgentService
|
||||
);
|
||||
service.display('', '', {}, [0, 0]);
|
||||
});
|
||||
it("when on phone device, positions at bottom", function () {
|
||||
mockAgentService.isPhone.andReturn(true);
|
||||
service = new InfoService(
|
||||
mockCompile,
|
||||
mockRootScope,
|
||||
mockPopupService,
|
||||
mockAgentService
|
||||
);
|
||||
service.display('', '', {}, [123, 456]);
|
||||
expect(mockPopupService.display).toHaveBeenCalledWith(
|
||||
mockElements[0],
|
||||
[ 0, -25 ],
|
||||
jasmine.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,14 @@ $colorKey: #0099cc;
|
||||
$colorKeySelectedBg: #005177;
|
||||
$colorKeyFg: #fff;
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.1);
|
||||
$colorA: #ccc;
|
||||
$colorAHov: #fff;
|
||||
$contrastRatioPercent: 7%;
|
||||
$basicCr: 2px;
|
||||
$controlCr: 3px;
|
||||
$smallCr: 2px;
|
||||
|
||||
// Buttons
|
||||
// Buttons and Controls
|
||||
$colorBtnBg: pullForward($colorBodyBg, $contrastRatioPercent); //
|
||||
$colorBtnFg: $colorBodyFg;
|
||||
$colorBtnMajorBg: $colorKey;
|
||||
@@ -20,6 +22,18 @@ $colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnIcon: $colorKey;
|
||||
$colorInvokeMenu: #fff;
|
||||
$contrastInvokeMenuPercent: 20%;
|
||||
$shdwBtns: rgba(black, 0.2) 0 1px 2px;
|
||||
$sliderColorBase: $colorKey;
|
||||
$sliderColorRangeHolder: rgba(black, 0.1);
|
||||
$sliderColorRange: rgba($sliderColorBase, 0.3);
|
||||
$sliderColorRangeHov: rgba($sliderColorBase, 0.5);
|
||||
$sliderColorKnob: rgba($sliderColorBase, 0.6);
|
||||
$sliderColorKnobHov: $sliderColorBase;
|
||||
$sliderColorRangeValHovBg: rgba($sliderColorBase, 0.1);
|
||||
$sliderColorRangeValHovFg: $colorKeyFg;
|
||||
$sliderKnobW: nth($ueTimeControlH,2)/2;
|
||||
$timeControllerToiLineColor: #00c2ff;
|
||||
$timeControllerToiLineColorHov: #fff;
|
||||
|
||||
// General Colors
|
||||
$colorAlt1: #ffc700;
|
||||
@@ -34,6 +48,7 @@ $colorFormSectionHeader: rgba(#000, 0.2);
|
||||
$colorInvokeMenu: #fff;
|
||||
$colorObjHdrTxt: $colorBodyFg;
|
||||
$colorObjHdrIc: pullForward($colorObjHdrTxt, 20%);
|
||||
$colorTick: rgba(white, 0.2);
|
||||
|
||||
// Menu colors
|
||||
$colorMenuBg: pullForward($colorBodyBg, 23%);
|
||||
@@ -99,16 +114,17 @@ $colorItemBgSelected: $colorKey;
|
||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
||||
$colorTabBodyBg: darken($colorBodyBg, 10%);
|
||||
$colorTabBodyFg: lighten($colorTabBodyBg, 40%);
|
||||
$colorTabHeaderBg: lighten($colorBodyBg, 10%);
|
||||
$colorTabHeaderFg: lighten($colorTabHeaderBg, 40%);
|
||||
$colorTabHeaderBg: rgba(white, 0.1); // lighten($colorBodyBg, 10%);
|
||||
$colorTabHeaderFg: $colorBodyFg; //lighten($colorTabHeaderBg, 40%);
|
||||
$colorTabHeaderBorder: $colorBodyBg;
|
||||
|
||||
// Plot
|
||||
$colorPlotBg: rgba(black, 0.1);
|
||||
$colorPlotFg: $colorBodyFg;
|
||||
$colorPlotHash: rgba(white, 0.2);
|
||||
$colorPlotHash: $colorTick;
|
||||
$stylePlotHash: dashed;
|
||||
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
|
||||
|
||||
// Tree
|
||||
$colorItemTreeIcon: $colorKey;
|
||||
@@ -139,5 +155,12 @@ $colorGrippyInteriorHover: $colorKey;
|
||||
// Mobile
|
||||
$colorMobilePaneLeft: darken($colorBodyBg, 5%);
|
||||
|
||||
// Datetime Picker
|
||||
$colorCalCellHovBg: $colorKey;
|
||||
$colorCalCellHovFg: $colorKeyFg;
|
||||
$colorCalCellSelectedBg: $colorItemTreeSelectedBg;
|
||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
|
||||
$colorCalCellInMonthBg: pushBack($colorMenuBg, 5%);
|
||||
|
||||
// About Screen
|
||||
$colorAboutLink: #84b3ff;
|
||||
@@ -1,13 +1,13 @@
|
||||
@mixin containerSubtle($bg: $colorBodyBg, $fg: $colorBodyFg, $hover: false) {
|
||||
@include containerBase($bg, $fg);
|
||||
@include background-image(linear-gradient(lighten($bg, 5%), $bg));
|
||||
@include boxShdwSubtle();
|
||||
@include boxShdw($shdwBtns);
|
||||
}
|
||||
|
||||
@mixin btnSubtle($bg: $colorBodyBg, $bgHov: none, $fg: $colorBodyFg, $ic: $colorBtnIcon) {
|
||||
@mixin btnSubtle($bg: $colorBodyBg, $bgHov: none, $fg: $colorBodyFg, $ic: $colorBtnIcon) {
|
||||
@include containerSubtle($bg, $fg);
|
||||
@include btnBase($bg, linear-gradient(lighten($bg, 15%), lighten($bg, 10%)), $fg, $ic);
|
||||
@include text-shadow(rgba(black, 0.3) 0 1px 1px);
|
||||
@include text-shadow($shdwItemText);
|
||||
}
|
||||
|
||||
@function pullForward($c: $colorBodyBg, $p: 20%) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,14 @@ $colorKey: #0099cc;
|
||||
$colorKeySelectedBg: $colorKey;
|
||||
$colorKeyFg: #fff;
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||
$colorA: #999;
|
||||
$colorAHov: $colorKey;
|
||||
$contrastRatioPercent: 40%;
|
||||
$basicCr: 4px;
|
||||
$controlCr: $basicCr;
|
||||
$smallCr: 3px;
|
||||
|
||||
// Buttons
|
||||
// Buttons and Controls
|
||||
$colorBtnBg: pullForward($colorBodyBg, $contrastRatioPercent);
|
||||
$colorBtnFg: #fff;
|
||||
$colorBtnMajorBg: $colorKey;
|
||||
@@ -20,6 +22,18 @@ $colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnIcon: #eee;
|
||||
$colorInvokeMenu: #000;
|
||||
$contrastInvokeMenuPercent: 40%;
|
||||
$shdwBtns: none;
|
||||
$sliderColorBase: $colorKey;
|
||||
$sliderColorRangeHolder: rgba(black, 0.07);
|
||||
$sliderColorRange: rgba($sliderColorBase, 0.2);
|
||||
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
|
||||
$sliderColorKnob: rgba($sliderColorBase, 0.5);
|
||||
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
|
||||
$sliderColorRangeValHovBg: $sliderColorRange; //rgba($sliderColorBase, 0.1);
|
||||
$sliderColorRangeValHovFg: $colorBodyFg;
|
||||
$sliderKnobW: nth($ueTimeControlH,2)/2;
|
||||
$timeControllerToiLineColor: $colorBodyFg;
|
||||
$timeControllerToiLineColorHov: #0052b5;
|
||||
|
||||
// General Colors
|
||||
$colorAlt1: #ff6600;
|
||||
@@ -32,6 +46,7 @@ $colorGridLines: rgba(#000, 0.05);
|
||||
$colorInvokeMenu: #fff;
|
||||
$colorObjHdrTxt: $colorBodyFg;
|
||||
$colorObjHdrIc: pushBack($colorObjHdrTxt, 30%);
|
||||
$colorTick: rgba(black, 0.2);
|
||||
|
||||
// Menu colors
|
||||
$colorMenuBg: pushBack($colorBodyBg, 10%);
|
||||
@@ -104,9 +119,10 @@ $colorTabHeaderBorder: $colorBodyBg;
|
||||
// Plot
|
||||
$colorPlotBg: rgba(black, 0.05);
|
||||
$colorPlotFg: $colorBodyFg;
|
||||
$colorPlotHash: rgba(black, 0.2);
|
||||
$colorPlotHash: $colorTick;
|
||||
$stylePlotHash: dashed;
|
||||
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
|
||||
|
||||
// Tree
|
||||
$colorItemTreeIcon: $colorKey;
|
||||
@@ -137,5 +153,12 @@ $colorGrippyInteriorHover: $colorBodyBg;
|
||||
// Mobile
|
||||
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
|
||||
|
||||
// Datetime Picker, Calendar
|
||||
$colorCalCellHovBg: $colorKey;
|
||||
$colorCalCellHovFg: $colorKeyFg;
|
||||
$colorCalCellSelectedBg: $colorItemTreeSelectedBg;
|
||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
|
||||
$colorCalCellInMonthBg: pullForward($colorMenuBg, 5%);
|
||||
|
||||
// About Screen
|
||||
$colorAboutLink: #84b3ff;
|
||||
@@ -1,5 +1,6 @@
|
||||
@mixin containerSubtle($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||
@include containerBase($bg, $fg);
|
||||
@include boxShdw($shdwBtns);
|
||||
}
|
||||
|
||||
@mixin btnSubtle($bg: $colorBtnBg, $bgHov: none, $fg: $colorBtnFg, $ic: $colorBtnIcon) {
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
"depends": [
|
||||
"persistenceService",
|
||||
"$q",
|
||||
"now",
|
||||
"PERSISTENCE_SPACE",
|
||||
"ADDITIONAL_PERSISTENCE_SPACES"
|
||||
]
|
||||
@@ -135,7 +136,7 @@
|
||||
"name": "Folder",
|
||||
"glyph": "F",
|
||||
"features": "creation",
|
||||
"description": "Useful for storing and organizing domain objects.",
|
||||
"description": "Create folders to organize other objects or links to objects.",
|
||||
"model": { "composition": [] }
|
||||
},
|
||||
{
|
||||
|
||||
@@ -29,7 +29,8 @@ define(
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var TOPIC_PREFIX = "mutation:";
|
||||
var GENERAL_TOPIC = "mutation",
|
||||
TOPIC_PREFIX = "mutation:";
|
||||
|
||||
// Utility function to overwrite a destination object
|
||||
// with the contents of a source object.
|
||||
@@ -78,7 +79,11 @@ define(
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function MutationCapability(topic, now, domainObject) {
|
||||
this.mutationTopic = topic(TOPIC_PREFIX + domainObject.getId());
|
||||
this.generalMutationTopic =
|
||||
topic(GENERAL_TOPIC);
|
||||
this.specificMutationTopic =
|
||||
topic(TOPIC_PREFIX + domainObject.getId());
|
||||
|
||||
this.now = now;
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
@@ -115,11 +120,17 @@ define(
|
||||
// mutator function has a temporary copy to work with.
|
||||
var domainObject = this.domainObject,
|
||||
now = this.now,
|
||||
t = this.mutationTopic,
|
||||
generalTopic = this.generalMutationTopic,
|
||||
specificTopic = this.specificMutationTopic,
|
||||
model = domainObject.getModel(),
|
||||
clone = JSON.parse(JSON.stringify(model)),
|
||||
useTimestamp = arguments.length > 1;
|
||||
|
||||
function notifyListeners(model) {
|
||||
generalTopic.notify(domainObject);
|
||||
specificTopic.notify(model);
|
||||
}
|
||||
|
||||
// Function to handle copying values to the actual
|
||||
function handleMutation(mutationResult) {
|
||||
// If mutation result was undefined, just use
|
||||
@@ -136,7 +147,7 @@ define(
|
||||
copyValues(model, result);
|
||||
}
|
||||
model.modified = useTimestamp ? timestamp : now();
|
||||
t.notify(model);
|
||||
notifyListeners(model);
|
||||
}
|
||||
|
||||
// Report the result of the mutation
|
||||
@@ -158,7 +169,7 @@ define(
|
||||
* @memberof platform/core.MutationCapability#
|
||||
*/
|
||||
MutationCapability.prototype.listen = function (listener) {
|
||||
return this.mutationTopic.listen(listener);
|
||||
return this.specificMutationTopic.listen(listener);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,14 +39,16 @@ define(
|
||||
* @param {PersistenceService} persistenceService the service in which
|
||||
* domain object models are persisted.
|
||||
* @param $q Angular's $q service, for working with promises
|
||||
* @param {function} now a function which provides the current time
|
||||
* @param {string} space the name of the persistence space(s)
|
||||
* from which models should be retrieved.
|
||||
* @param {string} spaces additional persistence spaces to use
|
||||
*/
|
||||
function PersistedModelProvider(persistenceService, $q, space, spaces) {
|
||||
function PersistedModelProvider(persistenceService, $q, now, space, spaces) {
|
||||
this.persistenceService = persistenceService;
|
||||
this.$q = $q;
|
||||
this.spaces = [space].concat(spaces || []);
|
||||
this.now = now;
|
||||
}
|
||||
|
||||
// Take the most recently modified model, for cases where
|
||||
@@ -61,7 +63,9 @@ define(
|
||||
PersistedModelProvider.prototype.getModels = function (ids) {
|
||||
var persistenceService = this.persistenceService,
|
||||
$q = this.$q,
|
||||
spaces = this.spaces;
|
||||
spaces = this.spaces,
|
||||
space = this.space,
|
||||
now = this.now;
|
||||
|
||||
// Load a single object model from any persistence spaces
|
||||
function loadModel(id) {
|
||||
@@ -72,11 +76,24 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure that models read from persistence have some
|
||||
// sensible timestamp indicating they've been persisted.
|
||||
function addPersistedTimestamp(model) {
|
||||
if (model && (model.persisted === undefined)) {
|
||||
model.persisted = model.modified !== undefined ?
|
||||
model.modified : now();
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
// Package the result as id->model
|
||||
function packageResult(models) {
|
||||
var result = {};
|
||||
ids.forEach(function (id, index) {
|
||||
result[id] = models[index];
|
||||
if (models[index]) {
|
||||
result[id] = addPersistedTimestamp(models[index]);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -36,11 +36,16 @@ define(
|
||||
*
|
||||
* Returns a function that, when invoked, will invoke `fn` after
|
||||
* `delay` milliseconds, only if no other invocations are pending.
|
||||
* The optional argument `apply` determines whether.
|
||||
* The optional argument `apply` determines whether or not a
|
||||
* digest cycle should be triggered.
|
||||
*
|
||||
* The returned function will itself return a `Promise` which will
|
||||
* resolve to the returned value of `fn` whenever that is invoked.
|
||||
*
|
||||
* In cases where arguments are provided, only the most recent
|
||||
* set of arguments will be passed on to the throttled function
|
||||
* at the time it is executed.
|
||||
*
|
||||
* @returns {Function}
|
||||
* @memberof platform/core
|
||||
*/
|
||||
@@ -56,12 +61,14 @@ define(
|
||||
* @memberof platform/core.Throttle#
|
||||
*/
|
||||
return function (fn, delay, apply) {
|
||||
var activeTimeout;
|
||||
var promise,
|
||||
args = [];
|
||||
|
||||
// Clear active timeout, so that next invocation starts
|
||||
// a new one.
|
||||
function clearActiveTimeout() {
|
||||
activeTimeout = undefined;
|
||||
function invoke() {
|
||||
// Clear the active timeout so a new one starts next time.
|
||||
promise = undefined;
|
||||
// Invoke the function with the latest supplied arguments.
|
||||
return fn.apply(null, args);
|
||||
}
|
||||
|
||||
// Defaults
|
||||
@@ -69,14 +76,13 @@ define(
|
||||
apply = apply || false;
|
||||
|
||||
return function () {
|
||||
// Store arguments from this invocation
|
||||
args = Array.prototype.slice.apply(arguments, [0]);
|
||||
// Start a timeout if needed
|
||||
if (!activeTimeout) {
|
||||
activeTimeout = $timeout(fn, delay, apply);
|
||||
activeTimeout.then(clearActiveTimeout);
|
||||
}
|
||||
promise = promise || $timeout(invoke, delay, apply);
|
||||
// Return whichever timeout is active (to get
|
||||
// a promise for the results of fn)
|
||||
return activeTimeout;
|
||||
return promise;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ define(
|
||||
SPACE = "space0",
|
||||
spaces = [ "space1" ],
|
||||
modTimes,
|
||||
mockNow,
|
||||
provider;
|
||||
|
||||
function mockPromise(value) {
|
||||
@@ -55,19 +56,33 @@ define(
|
||||
beforeEach(function () {
|
||||
modTimes = {};
|
||||
mockQ = { when: mockPromise, all: mockAll };
|
||||
mockPersistenceService = {
|
||||
readObject: function (space, id) {
|
||||
mockPersistenceService = jasmine.createSpyObj(
|
||||
'persistenceService',
|
||||
[
|
||||
'createObject',
|
||||
'readObject',
|
||||
'updateObject',
|
||||
'deleteObject',
|
||||
'listSpaces',
|
||||
'listObjects'
|
||||
]
|
||||
);
|
||||
mockNow = jasmine.createSpy("now");
|
||||
|
||||
mockPersistenceService.readObject
|
||||
.andCallFake(function (space, id) {
|
||||
return mockPromise({
|
||||
space: space,
|
||||
id: id,
|
||||
modified: (modTimes[space] || {})[id]
|
||||
modified: (modTimes[space] || {})[id],
|
||||
persisted: 0
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
provider = new PersistedModelProvider(
|
||||
mockPersistenceService,
|
||||
mockQ,
|
||||
mockNow,
|
||||
SPACE,
|
||||
spaces
|
||||
);
|
||||
@@ -81,12 +96,13 @@ define(
|
||||
});
|
||||
|
||||
expect(models).toEqual({
|
||||
a: { space: SPACE, id: "a" },
|
||||
x: { space: SPACE, id: "x" },
|
||||
zz: { space: SPACE, id: "zz" }
|
||||
a: { space: SPACE, id: "a", persisted: 0 },
|
||||
x: { space: SPACE, id: "x", persisted: 0 },
|
||||
zz: { space: SPACE, id: "zz", persisted: 0 }
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("reads object models from multiple spaces", function () {
|
||||
var models;
|
||||
|
||||
@@ -99,9 +115,36 @@ define(
|
||||
});
|
||||
|
||||
expect(models).toEqual({
|
||||
a: { space: SPACE, id: "a" },
|
||||
x: { space: 'space1', id: "x", modified: 12321 },
|
||||
zz: { space: SPACE, id: "zz" }
|
||||
a: { space: SPACE, id: "a", persisted: 0 },
|
||||
x: { space: 'space1', id: "x", modified: 12321, persisted: 0 },
|
||||
zz: { space: SPACE, id: "zz", persisted: 0 }
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("ensures that persisted timestamps are present", function () {
|
||||
var mockCallback = jasmine.createSpy("callback"),
|
||||
testModels = {
|
||||
a: { modified: 123, persisted: 1984, name: "A" },
|
||||
b: { persisted: 1977, name: "B" },
|
||||
c: { modified: 42, name: "C" },
|
||||
d: { name: "D" }
|
||||
};
|
||||
|
||||
mockPersistenceService.readObject.andCallFake(
|
||||
function (space, id) {
|
||||
return mockPromise(testModels[id]);
|
||||
}
|
||||
);
|
||||
mockNow.andReturn(12321);
|
||||
|
||||
provider.getModels(Object.keys(testModels)).then(mockCallback);
|
||||
|
||||
expect(mockCallback).toHaveBeenCalledWith({
|
||||
a: { modified: 123, persisted: 1984, name: "A" },
|
||||
b: { persisted: 1977, name: "B" },
|
||||
c: { modified: 42, persisted: 42, name: "C" },
|
||||
d: { persisted: 12321, name: "D" }
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ define(
|
||||
// Verify precondition: Not called at throttle-time
|
||||
expect(mockTimeout).not.toHaveBeenCalled();
|
||||
expect(throttled()).toEqual(mockPromise);
|
||||
expect(mockTimeout).toHaveBeenCalledWith(mockFn, 0, false);
|
||||
expect(mockFn).not.toHaveBeenCalled();
|
||||
expect(mockTimeout)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function), 0, false);
|
||||
});
|
||||
|
||||
it("schedules only one timeout at a time", function () {
|
||||
@@ -59,10 +61,11 @@ define(
|
||||
it("schedules additional invocations after resolution", function () {
|
||||
var throttled = throttle(mockFn);
|
||||
throttled();
|
||||
mockPromise.then.mostRecentCall.args[0](); // Resolve timeout
|
||||
mockTimeout.mostRecentCall.args[0](); // Resolve timeout
|
||||
throttled();
|
||||
mockPromise.then.mostRecentCall.args[0]();
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
throttled();
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
expect(mockTimeout.calls.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,14 +30,6 @@
|
||||
"category": "contextual",
|
||||
"implementation": "actions/LinkAction.js",
|
||||
"depends": ["locationService", "linkService"]
|
||||
},
|
||||
{
|
||||
"key": "follow",
|
||||
"name": "Go To Original",
|
||||
"description": "Go to the original, un-linked instance of this object.",
|
||||
"glyph": "\u00F4",
|
||||
"category": "contextual",
|
||||
"implementation": "actions/GoToOriginalAction.js"
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
@@ -60,8 +52,7 @@
|
||||
"key": "location",
|
||||
"name": "Location Capability",
|
||||
"description": "Provides a capability for retrieving the location of an object based upon it's context.",
|
||||
"implementation": "capabilities/LocationCapability",
|
||||
"depends": [ "$q", "$injector" ]
|
||||
"implementation": "capabilities/LocationCapability"
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
|
||||
@@ -12,41 +12,11 @@ define(
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function LocationCapability($q, $injector, domainObject) {
|
||||
function LocationCapability(domainObject) {
|
||||
this.domainObject = domainObject;
|
||||
this.$q = $q;
|
||||
this.$injector = $injector;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of this domain object in its original location.
|
||||
*
|
||||
* @returns {Promise.<DomainObject>} a promise for the original
|
||||
* instance of this domain object
|
||||
*/
|
||||
LocationCapability.prototype.getOriginal = function () {
|
||||
var id;
|
||||
|
||||
if (this.isOriginal()) {
|
||||
return this.$q.when(this.domainObject);
|
||||
}
|
||||
|
||||
id = this.domainObject.getId();
|
||||
|
||||
this.objectService =
|
||||
this.objectService || this.$injector.get("objectService");
|
||||
|
||||
// Assume that an object will be correctly contextualized when
|
||||
// loaded directly from the object service; this is true
|
||||
// so long as LocatingObjectDecorator is present, and that
|
||||
// decorator is also contained in this bundle.
|
||||
return this.objectService.getObjects([id])
|
||||
.then(function (objects) {
|
||||
return objects[id];
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the primary location (the parent id) of the current domain
|
||||
* object.
|
||||
@@ -108,6 +78,10 @@ define(
|
||||
return !this.isLink();
|
||||
};
|
||||
|
||||
return LocationCapability;
|
||||
function createLocationCapability(domainObject) {
|
||||
return new LocationCapability(domainObject);
|
||||
}
|
||||
|
||||
return createLocationCapability;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,95 +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.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define,describe,beforeEach,it,jasmine,expect */
|
||||
|
||||
define(
|
||||
[
|
||||
'../../src/actions/GoToOriginalAction',
|
||||
'../DomainObjectFactory',
|
||||
'../ControlledPromise'
|
||||
],
|
||||
function (GoToOriginalAction, domainObjectFactory, ControlledPromise) {
|
||||
'use strict';
|
||||
|
||||
describe("The 'go to original' action", function () {
|
||||
var testContext,
|
||||
originalDomainObject,
|
||||
mockLocationCapability,
|
||||
mockOriginalActionCapability,
|
||||
originalPromise,
|
||||
action;
|
||||
|
||||
beforeEach(function () {
|
||||
mockLocationCapability = jasmine.createSpyObj(
|
||||
'location',
|
||||
[ 'isLink', 'isOriginal', 'getOriginal' ]
|
||||
);
|
||||
mockOriginalActionCapability = jasmine.createSpyObj(
|
||||
'action',
|
||||
[ 'perform', 'getActions' ]
|
||||
);
|
||||
originalPromise = new ControlledPromise();
|
||||
mockLocationCapability.getOriginal.andReturn(originalPromise);
|
||||
mockLocationCapability.isLink.andReturn(true);
|
||||
mockLocationCapability.isOriginal.andCallFake(function () {
|
||||
return !mockLocationCapability.isLink();
|
||||
});
|
||||
testContext = {
|
||||
domainObject: domainObjectFactory({
|
||||
capabilities: {
|
||||
location: mockLocationCapability
|
||||
}
|
||||
})
|
||||
};
|
||||
originalDomainObject = domainObjectFactory({
|
||||
capabilities: {
|
||||
action: mockOriginalActionCapability
|
||||
}
|
||||
});
|
||||
|
||||
action = new GoToOriginalAction(testContext);
|
||||
});
|
||||
|
||||
it("is applicable to links", function () {
|
||||
expect(GoToOriginalAction.appliesTo(testContext))
|
||||
.toBeTruthy();
|
||||
});
|
||||
|
||||
it("is not applicable to originals", function () {
|
||||
mockLocationCapability.isLink.andReturn(false);
|
||||
expect(GoToOriginalAction.appliesTo(testContext))
|
||||
.toBeFalsy();
|
||||
});
|
||||
|
||||
it("navigates to original objects when performed", function () {
|
||||
expect(mockOriginalActionCapability.perform)
|
||||
.not.toHaveBeenCalled();
|
||||
action.perform();
|
||||
originalPromise.resolve(originalDomainObject);
|
||||
expect(mockOriginalActionCapability.perform)
|
||||
.toHaveBeenCalledWith('navigate');
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -7,7 +7,6 @@ define(
|
||||
'../ControlledPromise'
|
||||
],
|
||||
function (LocationCapability, domainObjectFactory, ControlledPromise) {
|
||||
'use strict';
|
||||
|
||||
describe("LocationCapability", function () {
|
||||
|
||||
@@ -15,17 +14,13 @@ define(
|
||||
var locationCapability,
|
||||
persistencePromise,
|
||||
mutationPromise,
|
||||
mockQ,
|
||||
mockInjector,
|
||||
mockObjectService,
|
||||
domainObject;
|
||||
|
||||
beforeEach(function () {
|
||||
domainObject = domainObjectFactory({
|
||||
id: "testObject",
|
||||
capabilities: {
|
||||
context: {
|
||||
getParent: function () {
|
||||
getParent: function() {
|
||||
return domainObjectFactory({id: 'root'});
|
||||
}
|
||||
},
|
||||
@@ -40,11 +35,6 @@ define(
|
||||
}
|
||||
});
|
||||
|
||||
mockQ = jasmine.createSpyObj("$q", ["when"]);
|
||||
mockInjector = jasmine.createSpyObj("$injector", ["get"]);
|
||||
mockObjectService =
|
||||
jasmine.createSpyObj("objectService", ["getObjects"]);
|
||||
|
||||
persistencePromise = new ControlledPromise();
|
||||
domainObject.capabilities.persistence.persist.andReturn(
|
||||
persistencePromise
|
||||
@@ -59,11 +49,7 @@ define(
|
||||
}
|
||||
);
|
||||
|
||||
locationCapability = new LocationCapability(
|
||||
mockQ,
|
||||
mockInjector,
|
||||
domainObject
|
||||
);
|
||||
locationCapability = new LocationCapability(domainObject);
|
||||
});
|
||||
|
||||
it("returns contextual location", function () {
|
||||
@@ -102,57 +88,6 @@ define(
|
||||
expect(whenComplete).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when used to load an original instance", function () {
|
||||
var objectPromise,
|
||||
qPromise,
|
||||
originalObjects,
|
||||
mockCallback;
|
||||
|
||||
function resolvePromises() {
|
||||
if (mockQ.when.calls.length > 0) {
|
||||
qPromise.resolve(mockQ.when.mostRecentCall.args[0]);
|
||||
}
|
||||
if (mockObjectService.getObjects.calls.length > 0) {
|
||||
objectPromise.resolve(originalObjects);
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
objectPromise = new ControlledPromise();
|
||||
qPromise = new ControlledPromise();
|
||||
originalObjects = {
|
||||
testObject: domainObjectFactory()
|
||||
};
|
||||
|
||||
mockInjector.get.andCallFake(function (key) {
|
||||
return key === 'objectService' && mockObjectService;
|
||||
});
|
||||
mockObjectService.getObjects.andReturn(objectPromise);
|
||||
mockQ.when.andReturn(qPromise);
|
||||
|
||||
mockCallback = jasmine.createSpy('callback');
|
||||
});
|
||||
|
||||
it("provides originals directly", function () {
|
||||
domainObject.model.location = 'root';
|
||||
locationCapability.getOriginal().then(mockCallback);
|
||||
expect(mockCallback).not.toHaveBeenCalled();
|
||||
resolvePromises();
|
||||
expect(mockCallback)
|
||||
.toHaveBeenCalledWith(domainObject);
|
||||
});
|
||||
|
||||
it("loads from the object service for links", function () {
|
||||
domainObject.model.location = 'some-other-root';
|
||||
locationCapability.getOriginal().then(mockCallback);
|
||||
expect(mockCallback).not.toHaveBeenCalled();
|
||||
resolvePromises();
|
||||
expect(mockCallback)
|
||||
.toHaveBeenCalledWith(originalObjects.testObject);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
[
|
||||
"actions/AbstractComposeAction",
|
||||
"actions/CopyAction",
|
||||
"actions/GoToOriginalAction",
|
||||
"actions/LinkAction",
|
||||
"actions/MoveAction",
|
||||
"services/CopyService",
|
||||
"services/LinkService",
|
||||
"services/MoveService",
|
||||
|
||||
9
platform/features/conductor/README.md
Normal file
9
platform/features/conductor/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
Provides the time conductor, a control which appears at the
|
||||
bottom of the screen allowing telemetry start and end times
|
||||
to be modified.
|
||||
|
||||
Note that the term "time controller" is generally preferred
|
||||
outside of the code base (e.g. in UI documents, issues, etc.);
|
||||
the term "time conductor" is being used in code to avoid
|
||||
confusion with "controllers" in the Model-View-Controller
|
||||
sense.
|
||||
46
platform/features/conductor/bundle.json
Normal file
46
platform/features/conductor/bundle.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"extensions": {
|
||||
"representers": [
|
||||
{
|
||||
"implementation": "ConductorRepresenter.js",
|
||||
"depends": [
|
||||
"throttle",
|
||||
"conductorService",
|
||||
"$compile",
|
||||
"views[]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"type": "decorator",
|
||||
"provides": "telemetryService",
|
||||
"implementation": "ConductorTelemetryDecorator.js",
|
||||
"depends": [ "conductorService" ]
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
{
|
||||
"key": "conductorService",
|
||||
"implementation": "ConductorService.js",
|
||||
"depends": [ "now", "TIME_CONDUCTOR_DOMAINS" ]
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"key": "time-conductor",
|
||||
"templateUrl": "templates/time-conductor.html"
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"key": "TIME_CONDUCTOR_DOMAINS",
|
||||
"value": [
|
||||
{ "key": "time", "name": "Time" },
|
||||
{ "key": "yesterday", "name": "Yesterday" }
|
||||
],
|
||||
"comment": "Placeholder; to be replaced by inspection of available domains."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<mct-include key="'time-controller'"
|
||||
ng-model='ngModel.conductor'>
|
||||
</mct-include>
|
||||
<mct-control key="'select'"
|
||||
ng-model='ngModel'
|
||||
field="'domain'"
|
||||
options="ngModel.options"
|
||||
style="position: absolute; right: 0px; bottom: 46px;"
|
||||
>
|
||||
</mct-control>
|
||||
201
platform/features/conductor/src/ConductorRepresenter.js
Normal file
201
platform/features/conductor/src/ConductorRepresenter.js
Normal file
@@ -0,0 +1,201 @@
|
||||
/*****************************************************************************
|
||||
* 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";
|
||||
|
||||
var TEMPLATE = [
|
||||
"<mct-include key=\"'time-conductor'\" ng-model='ngModel' class='l-time-controller'>",
|
||||
"</mct-include>"
|
||||
].join(''),
|
||||
THROTTLE_MS = 200,
|
||||
GLOBAL_SHOWING = false;
|
||||
|
||||
/**
|
||||
* The ConductorRepresenter attaches the universal time conductor
|
||||
* to views.
|
||||
*
|
||||
* @implements {Representer}
|
||||
* @constructor
|
||||
* @memberof platform/features/conductor
|
||||
* @param {Function} throttle a function used to reduce the frequency
|
||||
* of function invocations
|
||||
* @param {platform/features/conductor.ConductorService} conductorService
|
||||
* service which provides the active time conductor
|
||||
* @param $compile Angular's $compile
|
||||
* @param {ViewDefinition[]} views all defined views
|
||||
* @param {Scope} the scope of the representation
|
||||
* @param element the jqLite-wrapped representation element
|
||||
*/
|
||||
function ConductorRepresenter(
|
||||
throttle,
|
||||
conductorService,
|
||||
$compile,
|
||||
views,
|
||||
scope,
|
||||
element
|
||||
) {
|
||||
this.throttle = throttle;
|
||||
this.scope = scope;
|
||||
this.conductorService = conductorService;
|
||||
this.element = element;
|
||||
this.views = views;
|
||||
this.$compile = $compile;
|
||||
}
|
||||
|
||||
// Update the time conductor from the scope
|
||||
ConductorRepresenter.prototype.wireScope = function () {
|
||||
var conductor = this.conductorService.getConductor(),
|
||||
conductorScope = this.conductorScope(),
|
||||
repScope = this.scope,
|
||||
lastObservedBounds,
|
||||
broadcastBounds;
|
||||
|
||||
// Combine start/end times into a single object
|
||||
function bounds(start, end) {
|
||||
return {
|
||||
start: conductor.displayStart(),
|
||||
end: conductor.displayEnd(),
|
||||
domain: conductor.domain()
|
||||
};
|
||||
}
|
||||
|
||||
function boundsAreStable(newlyObservedBounds) {
|
||||
return !lastObservedBounds ||
|
||||
(lastObservedBounds.start === newlyObservedBounds.start &&
|
||||
lastObservedBounds.end === newlyObservedBounds.end);
|
||||
}
|
||||
|
||||
function updateConductorInner() {
|
||||
var innerBounds = conductorScope.ngModel.conductor.inner;
|
||||
conductor.displayStart(innerBounds.start);
|
||||
conductor.displayEnd(innerBounds.end);
|
||||
lastObservedBounds = lastObservedBounds || bounds();
|
||||
broadcastBounds();
|
||||
}
|
||||
|
||||
function updateDomain(value) {
|
||||
conductor.domain(value);
|
||||
repScope.$broadcast('telemetry:display:bounds', bounds(
|
||||
conductor.displayStart(),
|
||||
conductor.displayEnd(),
|
||||
conductor.domain()
|
||||
));
|
||||
}
|
||||
|
||||
// telemetry domain metadata -> option for a select control
|
||||
function makeOption(domainOption) {
|
||||
return {
|
||||
name: domainOption.name,
|
||||
value: domainOption.key
|
||||
};
|
||||
}
|
||||
|
||||
broadcastBounds = this.throttle(function () {
|
||||
var newlyObservedBounds = bounds();
|
||||
|
||||
if (boundsAreStable(newlyObservedBounds)) {
|
||||
repScope.$broadcast('telemetry:display:bounds', bounds());
|
||||
lastObservedBounds = undefined;
|
||||
} else {
|
||||
lastObservedBounds = newlyObservedBounds;
|
||||
broadcastBounds();
|
||||
}
|
||||
}, THROTTLE_MS);
|
||||
|
||||
conductorScope.ngModel = {};
|
||||
conductorScope.ngModel.conductor =
|
||||
{ outer: bounds(), inner: bounds() };
|
||||
conductorScope.ngModel.options =
|
||||
conductor.domainOptions().map(makeOption);
|
||||
conductorScope.ngModel.domain = conductor.domain();
|
||||
|
||||
conductorScope
|
||||
.$watch('ngModel.conductor.inner.start', updateConductorInner);
|
||||
conductorScope
|
||||
.$watch('ngModel.conductor.inner.end', updateConductorInner);
|
||||
conductorScope
|
||||
.$watch('ngModel.domain', updateDomain);
|
||||
|
||||
repScope.$on('telemetry:view', updateConductorInner);
|
||||
};
|
||||
|
||||
ConductorRepresenter.prototype.conductorScope = function (s) {
|
||||
return (this.cScope = arguments.length > 0 ? s : this.cScope);
|
||||
};
|
||||
|
||||
// Handle a specific representation of a specific domain object
|
||||
ConductorRepresenter.prototype.represent = function represent(representation, representedObject) {
|
||||
this.destroy();
|
||||
|
||||
if (this.views.indexOf(representation) !== -1 && !GLOBAL_SHOWING) {
|
||||
// Track original states
|
||||
this.originalHeight = this.element.css('height');
|
||||
this.hadAbs = this.element.hasClass('abs');
|
||||
|
||||
// Create a new scope for the conductor
|
||||
this.conductorScope(this.scope.$new());
|
||||
this.wireScope();
|
||||
this.conductorElement =
|
||||
this.$compile(TEMPLATE)(this.conductorScope());
|
||||
this.element.after(this.conductorElement[0]);
|
||||
this.element.addClass('l-controls-visible l-time-controller-visible');
|
||||
GLOBAL_SHOWING = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Respond to the destruction of the current representation.
|
||||
ConductorRepresenter.prototype.destroy = function destroy() {
|
||||
// We may not have decided to show in the first place,
|
||||
// so circumvent any unnecessary cleanup
|
||||
if (!this.conductorElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore the original size of the mct-representation
|
||||
if (!this.hadAbs) {
|
||||
this.element.removeClass('abs');
|
||||
}
|
||||
this.element.css('height', this.originalHeight);
|
||||
|
||||
// ...and remove the conductor
|
||||
if (this.conductorElement) {
|
||||
this.conductorElement.remove();
|
||||
this.conductorElement = undefined;
|
||||
}
|
||||
|
||||
// Finally, destroy its scope
|
||||
if (this.conductorScope()) {
|
||||
this.conductorScope().$destroy();
|
||||
this.conductorScope(undefined);
|
||||
}
|
||||
|
||||
GLOBAL_SHOWING = false;
|
||||
};
|
||||
|
||||
return ConductorRepresenter;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -19,44 +19,46 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/*global define */
|
||||
define(
|
||||
function () {
|
||||
"use strict";
|
||||
['./TimeConductor'],
|
||||
function (TimeConductor) {
|
||||
'use strict';
|
||||
|
||||
var ONE_DAY_IN_MS = 1000 * 60 * 60 * 24,
|
||||
SIX_HOURS_IN_MS = ONE_DAY_IN_MS / 4;
|
||||
|
||||
/**
|
||||
* Implements the "Go To Original" action, which follows a link back
|
||||
* to an original instance of an object.
|
||||
* Provides a single global instance of the time conductor, which
|
||||
* controls both query ranges and displayed ranges for telemetry
|
||||
* data.
|
||||
*
|
||||
* @implements {Action}
|
||||
* @constructor
|
||||
* @private
|
||||
* @memberof platform/entanglement
|
||||
* @param {ActionContext} context the context in which the action
|
||||
* will be performed
|
||||
* @memberof platform/features/conductor
|
||||
* @param {Function} now a function which returns the current time
|
||||
* as a UNIX timestamp, in milliseconds
|
||||
*/
|
||||
function GoToOriginalAction(context) {
|
||||
this.domainObject = context.domainObject;
|
||||
function ConductorService(now, domains) {
|
||||
var initialEnd =
|
||||
Math.ceil(now() / SIX_HOURS_IN_MS) * SIX_HOURS_IN_MS;
|
||||
|
||||
this.conductor = new TimeConductor(
|
||||
initialEnd - ONE_DAY_IN_MS,
|
||||
initialEnd,
|
||||
domains
|
||||
);
|
||||
}
|
||||
|
||||
GoToOriginalAction.prototype.perform = function () {
|
||||
return this.domainObject.getCapability("location").getOriginal()
|
||||
.then(function (originalObject) {
|
||||
var actionCapability =
|
||||
originalObject.getCapability("action");
|
||||
return actionCapability &&
|
||||
actionCapability.perform("navigate");
|
||||
});
|
||||
/**
|
||||
* Get the global instance of the time conductor.
|
||||
* @returns {platform/features/conductor.TimeConductor} the
|
||||
* time conductor
|
||||
*/
|
||||
ConductorService.prototype.getConductor = function () {
|
||||
return this.conductor;
|
||||
};
|
||||
|
||||
GoToOriginalAction.appliesTo = function (context) {
|
||||
var domainObject = context.domainObject;
|
||||
return domainObject && domainObject.hasCapability("location")
|
||||
&& domainObject.getCapability("location").isLink();
|
||||
};
|
||||
|
||||
return GoToOriginalAction;
|
||||
return ConductorService;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
/**
|
||||
* Decorates the `telemetryService` such that requests are
|
||||
* mediated by the time conductor.
|
||||
*
|
||||
* @constructor
|
||||
* @memberof platform/features/conductor
|
||||
* @implements {TelemetryService}
|
||||
* @param {platform/features/conductor.ConductorService} conductorServe
|
||||
* the service which exposes the global time conductor
|
||||
* @param {TelemetryService} telemetryService the decorated service
|
||||
*/
|
||||
function ConductorTelemetryDecorator(conductorService, telemetryService) {
|
||||
this.conductorService = conductorService;
|
||||
this.telemetryService = telemetryService;
|
||||
}
|
||||
|
||||
ConductorTelemetryDecorator.prototype.amendRequests = function (requests) {
|
||||
var conductor = this.conductorService.getConductor(),
|
||||
start = conductor.displayStart(),
|
||||
end = conductor.displayEnd(),
|
||||
domain = conductor.domain();
|
||||
|
||||
function amendRequest(request) {
|
||||
request = request || {};
|
||||
request.start = start;
|
||||
request.end = end;
|
||||
request.domain = domain;
|
||||
return request;
|
||||
}
|
||||
|
||||
return (requests || []).map(amendRequest);
|
||||
};
|
||||
|
||||
ConductorTelemetryDecorator.prototype.requestTelemetry = function (requests) {
|
||||
var self = this;
|
||||
return this.telemetryService
|
||||
.requestTelemetry(this.amendRequests(requests));
|
||||
};
|
||||
|
||||
ConductorTelemetryDecorator.prototype.subscribe = function (callback, requests) {
|
||||
var self = this;
|
||||
|
||||
return this.telemetryService
|
||||
.subscribe(callback, this.amendRequests(requests));
|
||||
};
|
||||
|
||||
return ConductorTelemetryDecorator;
|
||||
}
|
||||
);
|
||||
103
platform/features/conductor/src/TimeConductor.js
Normal file
103
platform/features/conductor/src/TimeConductor.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* The time conductor bundle adds a global control to the bottom of the
|
||||
* outermost viewing area. This controls both the range for time-based
|
||||
* queries and for time-based displays.
|
||||
*
|
||||
* @namespace platform/features/conductor
|
||||
*/
|
||||
define(
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Tracks the current state of the time conductor.
|
||||
*
|
||||
* @memberof platform/features/conductor
|
||||
* @constructor
|
||||
* @param {number} start the initial start time
|
||||
* @param {number} end the initial end time
|
||||
*/
|
||||
function TimeConductor(start, end, domains) {
|
||||
this.range = { start: start, end: end };
|
||||
this.domains = domains;
|
||||
this.activeDomain = domains[0].key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set (if called with an argument) the start time for displays.
|
||||
* @param {number} [value] the start time to set
|
||||
* @returns {number} the start time
|
||||
*/
|
||||
TimeConductor.prototype.displayStart = function (value) {
|
||||
if (arguments.length > 0) {
|
||||
this.range.start = value;
|
||||
}
|
||||
return this.range.start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get or set (if called with an argument) the end time for displays.
|
||||
* @param {number} [value] the end time to set
|
||||
* @returns {number} the end time
|
||||
*/
|
||||
TimeConductor.prototype.displayEnd = function (value) {
|
||||
if (arguments.length > 0) {
|
||||
this.range.end = value;
|
||||
}
|
||||
return this.range.end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get available domain options which can be used to bound time
|
||||
* selection.
|
||||
* @returns {TelemetryDomain[]} available domains
|
||||
*/
|
||||
TimeConductor.prototype.domainOptions = function () {
|
||||
return this.domains;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get or set (if called with an argument) the active domain.
|
||||
* @param {string} [key] the key identifying the domain choice
|
||||
* @returns {TelemetryDomain} the active telemetry domain
|
||||
*/
|
||||
TimeConductor.prototype.domain = function (key) {
|
||||
function matchesKey(domain) {
|
||||
return domain.key === key;
|
||||
}
|
||||
|
||||
if (arguments.length > 0) {
|
||||
if (!this.domains.some(matchesKey)) {
|
||||
throw new Error("Unknown domain " + key);
|
||||
}
|
||||
this.activeDomain = key;
|
||||
}
|
||||
return this.activeDomain;
|
||||
};
|
||||
|
||||
return TimeConductor;
|
||||
}
|
||||
);
|
||||
259
platform/features/conductor/test/ConductorRepresenterSpec.js
Normal file
259
platform/features/conductor/test/ConductorRepresenterSpec.js
Normal file
@@ -0,0 +1,259 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,waitsFor,afterEach,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/ConductorRepresenter", "./TestTimeConductor"],
|
||||
function (ConductorRepresenter, TestTimeConductor) {
|
||||
"use strict";
|
||||
|
||||
var SCOPE_METHODS = [
|
||||
'$on',
|
||||
'$watch',
|
||||
'$broadcast',
|
||||
'$emit',
|
||||
'$new',
|
||||
'$destroy'
|
||||
],
|
||||
ELEMENT_METHODS = [
|
||||
'hasClass',
|
||||
'addClass',
|
||||
'removeClass',
|
||||
'css',
|
||||
'after',
|
||||
'remove'
|
||||
];
|
||||
|
||||
describe("ConductorRepresenter", function () {
|
||||
var mockThrottle,
|
||||
mockConductorService,
|
||||
mockCompile,
|
||||
testViews,
|
||||
mockScope,
|
||||
mockElement,
|
||||
mockConductor,
|
||||
mockCompiledTemplate,
|
||||
mockNewScope,
|
||||
mockNewElement,
|
||||
representer;
|
||||
|
||||
function fireWatch(scope, watch, value) {
|
||||
scope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === watch) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockThrottle = jasmine.createSpy('throttle');
|
||||
mockConductorService = jasmine.createSpyObj(
|
||||
'conductorService',
|
||||
['getConductor']
|
||||
);
|
||||
mockCompile = jasmine.createSpy('$compile');
|
||||
testViews = [ { someKey: "some value" } ];
|
||||
mockScope = jasmine.createSpyObj('scope', SCOPE_METHODS);
|
||||
mockElement = jasmine.createSpyObj('element', ELEMENT_METHODS);
|
||||
mockConductor = new TestTimeConductor();
|
||||
mockCompiledTemplate = jasmine.createSpy('template');
|
||||
mockNewScope = jasmine.createSpyObj('newScope', SCOPE_METHODS);
|
||||
mockNewElement = jasmine.createSpyObj('newElement', ELEMENT_METHODS);
|
||||
mockNewElement[0] = mockNewElement;
|
||||
|
||||
mockConductorService.getConductor.andReturn(mockConductor);
|
||||
mockCompile.andReturn(mockCompiledTemplate);
|
||||
mockCompiledTemplate.andReturn(mockNewElement);
|
||||
mockScope.$new.andReturn(mockNewScope);
|
||||
mockThrottle.andCallFake(function (fn) {
|
||||
return fn;
|
||||
});
|
||||
|
||||
representer = new ConductorRepresenter(
|
||||
mockThrottle,
|
||||
mockConductorService,
|
||||
mockCompile,
|
||||
testViews,
|
||||
mockScope,
|
||||
mockElement
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
representer.destroy();
|
||||
});
|
||||
|
||||
it("adds a conductor to views", function () {
|
||||
representer.represent(testViews[0], {});
|
||||
expect(mockElement.after).toHaveBeenCalledWith(mockNewElement);
|
||||
});
|
||||
|
||||
it("adds nothing to non-view representations", function () {
|
||||
representer.represent({ someKey: "something else" }, {});
|
||||
expect(mockElement.after).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("removes the conductor when destroyed", function () {
|
||||
representer.represent(testViews[0], {});
|
||||
expect(mockNewElement.remove).not.toHaveBeenCalled();
|
||||
representer.destroy();
|
||||
expect(mockNewElement.remove).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("destroys any new scope created", function () {
|
||||
representer.represent(testViews[0], {});
|
||||
representer.destroy();
|
||||
expect(mockNewScope.$destroy.calls.length)
|
||||
.toEqual(mockScope.$new.calls.length);
|
||||
});
|
||||
|
||||
it("exposes conductor state in scope", function () {
|
||||
mockConductor.displayStart.andReturn(1977);
|
||||
mockConductor.displayEnd.andReturn(1984);
|
||||
mockConductor.domain.andReturn('d');
|
||||
representer.represent(testViews[0], {});
|
||||
|
||||
expect(mockNewScope.ngModel.conductor).toEqual({
|
||||
inner: { start: 1977, end: 1984, domain: 'd' },
|
||||
outer: { start: 1977, end: 1984, domain: 'd' }
|
||||
});
|
||||
});
|
||||
|
||||
it("updates conductor state from scope", function () {
|
||||
var testState = {
|
||||
inner: { start: 42, end: 1984 },
|
||||
outer: { start: -1977, end: 12321 }
|
||||
};
|
||||
|
||||
representer.represent(testViews[0], {});
|
||||
|
||||
mockNewScope.ngModel.conductor = testState;
|
||||
|
||||
fireWatch(
|
||||
mockNewScope,
|
||||
'ngModel.conductor.inner.start',
|
||||
testState.inner.start
|
||||
);
|
||||
expect(mockConductor.displayStart).toHaveBeenCalledWith(42);
|
||||
|
||||
fireWatch(
|
||||
mockNewScope,
|
||||
'ngModel.conductor.inner.end',
|
||||
testState.inner.end
|
||||
);
|
||||
expect(mockConductor.displayEnd).toHaveBeenCalledWith(1984);
|
||||
});
|
||||
|
||||
describe("when bounds are changing", function () {
|
||||
var startWatch = "ngModel.conductor.inner.start",
|
||||
endWatch = "ngModel.conductor.inner.end",
|
||||
mockThrottledFn = jasmine.createSpy('throttledFn'),
|
||||
testBounds;
|
||||
|
||||
function fireThrottledFn() {
|
||||
mockThrottle.mostRecentCall.args[0]();
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockThrottle.andReturn(mockThrottledFn);
|
||||
representer.represent(testViews[0], {});
|
||||
testBounds = { start: 0, end: 1000 };
|
||||
mockNewScope.ngModel.conductor.inner = testBounds;
|
||||
mockConductor.displayStart.andCallFake(function () {
|
||||
return testBounds.start;
|
||||
});
|
||||
mockConductor.displayEnd.andCallFake(function () {
|
||||
return testBounds.end;
|
||||
});
|
||||
});
|
||||
|
||||
it("does not broadcast while bounds are changing", function () {
|
||||
expect(mockScope.$broadcast).not.toHaveBeenCalled();
|
||||
testBounds.start = 100;
|
||||
fireWatch(mockNewScope, startWatch, testBounds.start);
|
||||
testBounds.end = 500;
|
||||
fireWatch(mockNewScope, endWatch, testBounds.end);
|
||||
fireThrottledFn();
|
||||
testBounds.start = 200;
|
||||
fireWatch(mockNewScope, startWatch, testBounds.start);
|
||||
testBounds.end = 400;
|
||||
fireWatch(mockNewScope, endWatch, testBounds.end);
|
||||
fireThrottledFn();
|
||||
expect(mockScope.$broadcast).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does broadcast when bounds have stabilized", function () {
|
||||
expect(mockScope.$broadcast).not.toHaveBeenCalled();
|
||||
testBounds.start = 100;
|
||||
fireWatch(mockNewScope, startWatch, testBounds.start);
|
||||
testBounds.end = 500;
|
||||
fireWatch(mockNewScope, endWatch, testBounds.end);
|
||||
fireThrottledFn();
|
||||
fireWatch(mockNewScope, startWatch, testBounds.start);
|
||||
fireWatch(mockNewScope, endWatch, testBounds.end);
|
||||
fireThrottledFn();
|
||||
expect(mockScope.$broadcast).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes domain selection in scope", function () {
|
||||
representer.represent(testViews[0], null);
|
||||
|
||||
expect(mockNewScope.ngModel.domain)
|
||||
.toEqual(mockConductor.domain());
|
||||
});
|
||||
|
||||
it("exposes domain options in scope", function () {
|
||||
representer.represent(testViews[0], null);
|
||||
|
||||
mockConductor.domainOptions().forEach(function (option, i) {
|
||||
expect(mockNewScope.ngModel.options[i].value)
|
||||
.toEqual(option.key);
|
||||
expect(mockNewScope.ngModel.options[i].name)
|
||||
.toEqual(option.name);
|
||||
});
|
||||
});
|
||||
|
||||
it("updates domain selection from scope", function () {
|
||||
var choice;
|
||||
representer.represent(testViews[0], null);
|
||||
|
||||
// Choose a domain that isn't currently selected
|
||||
mockNewScope.ngModel.options.forEach(function (option) {
|
||||
if (option.value !== mockNewScope.ngModel.domain) {
|
||||
choice = option.value;
|
||||
}
|
||||
});
|
||||
|
||||
expect(mockConductor.domain)
|
||||
.not.toHaveBeenCalledWith(choice);
|
||||
|
||||
mockNewScope.ngModel.domain = choice;
|
||||
fireWatch(mockNewScope, "ngModel.domain", choice);
|
||||
|
||||
expect(mockConductor.domain)
|
||||
.toHaveBeenCalledWith(choice);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
58
platform/features/conductor/test/ConductorServiceSpec.js
Normal file
58
platform/features/conductor/test/ConductorServiceSpec.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/ConductorService"],
|
||||
function (ConductorService) {
|
||||
"use strict";
|
||||
|
||||
var TEST_NOW = 1020304050;
|
||||
|
||||
describe("ConductorService", function () {
|
||||
var mockNow,
|
||||
conductorService;
|
||||
|
||||
beforeEach(function () {
|
||||
mockNow = jasmine.createSpy('now');
|
||||
mockNow.andReturn(TEST_NOW);
|
||||
conductorService = new ConductorService(mockNow, [
|
||||
{ key: "d1", name: "Domain #1" },
|
||||
{ key: "d2", name: "Domain #2" }
|
||||
]);
|
||||
});
|
||||
|
||||
it("initializes a time conductor around the current time", function () {
|
||||
var conductor = conductorService.getConductor();
|
||||
expect(conductor.displayStart() <= TEST_NOW).toBeTruthy();
|
||||
expect(conductor.displayEnd() >= TEST_NOW).toBeTruthy();
|
||||
expect(conductor.displayEnd() > conductor.displayStart())
|
||||
.toBeTruthy();
|
||||
});
|
||||
|
||||
it("provides a single shared time conductor instance", function () {
|
||||
expect(conductorService.getConductor())
|
||||
.toBe(conductorService.getConductor());
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,160 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
|
||||
define(
|
||||
["../src/ConductorTelemetryDecorator", "./TestTimeConductor"],
|
||||
function (ConductorTelemetryDecorator, TestTimeConductor) {
|
||||
"use strict";
|
||||
|
||||
describe("ConductorTelemetryDecorator", function () {
|
||||
var mockTelemetryService,
|
||||
mockConductorService,
|
||||
mockConductor,
|
||||
mockPromise,
|
||||
mockSeries,
|
||||
decorator;
|
||||
|
||||
function seriesIsInWindow(series) {
|
||||
var i, v, inWindow = true;
|
||||
for (i = 0; i < series.getPointCount(); i += 1) {
|
||||
v = series.getDomainValue(i);
|
||||
inWindow = inWindow && (v >= mockConductor.displayStart());
|
||||
inWindow = inWindow && (v <= mockConductor.displayEnd());
|
||||
}
|
||||
return inWindow;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockTelemetryService = jasmine.createSpyObj(
|
||||
'telemetryService',
|
||||
[ 'requestTelemetry', 'subscribe' ]
|
||||
);
|
||||
mockConductorService = jasmine.createSpyObj(
|
||||
'conductorService',
|
||||
['getConductor']
|
||||
);
|
||||
mockConductor = new TestTimeConductor();
|
||||
mockPromise = jasmine.createSpyObj(
|
||||
'promise',
|
||||
['then']
|
||||
);
|
||||
mockSeries = jasmine.createSpyObj(
|
||||
'series',
|
||||
[ 'getPointCount', 'getDomainValue', 'getRangeValue' ]
|
||||
);
|
||||
|
||||
mockTelemetryService.requestTelemetry.andReturn(mockPromise);
|
||||
mockConductorService.getConductor.andReturn(mockConductor);
|
||||
|
||||
// Prepare test series; make sure it has a broad range of
|
||||
// domain values, with at least some in the query-able range
|
||||
mockSeries.getPointCount.andReturn(1000);
|
||||
mockSeries.getDomainValue.andCallFake(function (i) {
|
||||
var j = i - 500;
|
||||
return j * j * j;
|
||||
});
|
||||
|
||||
mockConductor.displayStart.andReturn(42);
|
||||
mockConductor.displayEnd.andReturn(1977);
|
||||
mockConductor.domain.andReturn("testDomain");
|
||||
|
||||
decorator = new ConductorTelemetryDecorator(
|
||||
mockConductorService,
|
||||
mockTelemetryService
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
describe("decorates historical requests", function () {
|
||||
var request;
|
||||
|
||||
beforeEach(function () {
|
||||
decorator.requestTelemetry([{ someKey: "some value" }]);
|
||||
request = mockTelemetryService.requestTelemetry
|
||||
.mostRecentCall.args[0][0];
|
||||
});
|
||||
|
||||
it("with start times", function () {
|
||||
expect(request.start).toEqual(mockConductor.displayStart());
|
||||
});
|
||||
|
||||
it("with end times", function () {
|
||||
expect(request.end).toEqual(mockConductor.displayEnd());
|
||||
});
|
||||
|
||||
it("with domain selection", function () {
|
||||
expect(request.domain).toEqual(mockConductor.domain());
|
||||
});
|
||||
});
|
||||
|
||||
describe("decorates subscription requests", function () {
|
||||
var request;
|
||||
|
||||
beforeEach(function () {
|
||||
var mockCallback = jasmine.createSpy('callback');
|
||||
decorator.subscribe(mockCallback, [{ someKey: "some value" }]);
|
||||
request = mockTelemetryService.subscribe
|
||||
.mostRecentCall.args[1][0];
|
||||
});
|
||||
|
||||
it("with start times", function () {
|
||||
expect(request.start).toEqual(mockConductor.displayStart());
|
||||
});
|
||||
|
||||
it("with end times", function () {
|
||||
expect(request.end).toEqual(mockConductor.displayEnd());
|
||||
});
|
||||
|
||||
it("with domain selection", function () {
|
||||
expect(request.domain).toEqual(mockConductor.domain());
|
||||
});
|
||||
});
|
||||
|
||||
it("adds display start/end times & domain selection to historical requests", function () {
|
||||
decorator.requestTelemetry([{ someKey: "some value" }]);
|
||||
expect(mockTelemetryService.requestTelemetry)
|
||||
.toHaveBeenCalledWith([{
|
||||
someKey: "some value",
|
||||
start: mockConductor.displayStart(),
|
||||
end: mockConductor.displayEnd(),
|
||||
domain: jasmine.any(String)
|
||||
}]);
|
||||
});
|
||||
|
||||
it("adds display start/end times & domain selection to subscription requests", function () {
|
||||
var mockCallback = jasmine.createSpy('callback');
|
||||
decorator.subscribe(mockCallback, [{ someKey: "some value" }]);
|
||||
expect(mockTelemetryService.subscribe)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function), [{
|
||||
someKey: "some value",
|
||||
start: mockConductor.displayStart(),
|
||||
end: mockConductor.displayEnd(),
|
||||
domain: jasmine.any(String)
|
||||
}]);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
50
platform/features/conductor/test/TestTimeConductor.js
Normal file
50
platform/features/conductor/test/TestTimeConductor.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,waitsFor,jasmine,spyOn*/
|
||||
|
||||
define(
|
||||
["../src/TimeConductor"],
|
||||
function (TimeConductor) {
|
||||
'use strict';
|
||||
|
||||
function TestTimeConductor() {
|
||||
var self = this;
|
||||
|
||||
TimeConductor.apply(this, [
|
||||
402514200000,
|
||||
444546000000,
|
||||
[
|
||||
{ key: "domain0", name: "Domain #1" },
|
||||
{ key: "domain1", name: "Domain #2" }
|
||||
]
|
||||
]);
|
||||
|
||||
Object.keys(TimeConductor.prototype).forEach(function (method) {
|
||||
spyOn(self, method).andCallThrough();
|
||||
});
|
||||
}
|
||||
|
||||
TestTimeConductor.prototype = TimeConductor.prototype;
|
||||
|
||||
return TestTimeConductor;
|
||||
}
|
||||
);
|
||||
78
platform/features/conductor/test/TimeConductorSpec.js
Normal file
78
platform/features/conductor/test/TimeConductorSpec.js
Normal file
@@ -0,0 +1,78 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/TimeConductor"],
|
||||
function (TimeConductor) {
|
||||
"use strict";
|
||||
|
||||
describe("TimeConductor", function () {
|
||||
var testStart,
|
||||
testEnd,
|
||||
testDomains,
|
||||
conductor;
|
||||
|
||||
beforeEach(function () {
|
||||
testStart = 42;
|
||||
testEnd = 12321;
|
||||
testDomains = [
|
||||
{ key: "d1", name: "Domain #1" },
|
||||
{ key: "d2", name: "Domain #2" }
|
||||
];
|
||||
conductor = new TimeConductor(testStart, testEnd, testDomains);
|
||||
});
|
||||
|
||||
it("provides accessors for query/display start/end times", function () {
|
||||
expect(conductor.displayStart()).toEqual(testStart);
|
||||
expect(conductor.displayEnd()).toEqual(testEnd);
|
||||
});
|
||||
|
||||
it("provides setters for query/display start/end times", function () {
|
||||
expect(conductor.displayStart(3)).toEqual(3);
|
||||
expect(conductor.displayEnd(4)).toEqual(4);
|
||||
expect(conductor.displayStart()).toEqual(3);
|
||||
expect(conductor.displayEnd()).toEqual(4);
|
||||
});
|
||||
|
||||
it("exposes domain options", function () {
|
||||
expect(conductor.domainOptions()).toEqual(testDomains);
|
||||
});
|
||||
|
||||
it("exposes the current domain choice", function () {
|
||||
expect(conductor.domain()).toEqual(testDomains[0].key);
|
||||
});
|
||||
|
||||
it("allows the domain choice to be changed", function () {
|
||||
conductor.domain(testDomains[1].key);
|
||||
expect(conductor.domain()).toEqual(testDomains[1].key);
|
||||
});
|
||||
|
||||
it("throws an error on attempts to set an invalid domain", function () {
|
||||
expect(function () {
|
||||
conductor.domain("invalid-domain");
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
6
platform/features/conductor/test/suite.json
Normal file
6
platform/features/conductor/test/suite.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
"ConductorRepresenter",
|
||||
"ConductorService",
|
||||
"ConductorTelemetryDecorator",
|
||||
"TimeConductor"
|
||||
]
|
||||
@@ -167,8 +167,9 @@
|
||||
"$scope",
|
||||
"$q",
|
||||
"dialogService",
|
||||
"telemetrySubscriber",
|
||||
"telemetryFormatter"
|
||||
"telemetryHandler",
|
||||
"telemetryFormatter",
|
||||
"throttle"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -205,7 +206,7 @@
|
||||
"key": "layout",
|
||||
"name": "Display Layout",
|
||||
"glyph": "L",
|
||||
"description": "A layout in which multiple telemetry panels may be displayed.",
|
||||
"description": "Assemble other objects and components together into a reusable screen layout. Working in a simple canvas workspace, simply drag in the objects you want, position and size them. Save your design and view or edit it at any time.",
|
||||
"features": "creation",
|
||||
"model": { "composition": [] },
|
||||
"properties": [
|
||||
@@ -234,7 +235,7 @@
|
||||
"key": "telemetry.panel",
|
||||
"name": "Telemetry Panel",
|
||||
"glyph": "t",
|
||||
"description": "A panel for collecting telemetry elements.",
|
||||
"description": "Combine telemetry elements into a reusable dashboard component. Telemetry Panels can be viewed in a variety of ways: plot, scrolling list and a Fixed Position canvas view. The Fixed Position view can include images, boxes and lines allowing you to create rich, graphic displays overlaid with live data. Can be added to Display Layouts.",
|
||||
"delegates": [ "telemetry" ],
|
||||
"features": "creation",
|
||||
"contains": [ { "has": "telemetry" } ],
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div style="width: 100%; height: 100%;"
|
||||
<div class="l-layout"
|
||||
ng-controller="LayoutController as controller">
|
||||
|
||||
<div class='frame child-frame panel abs'
|
||||
|
||||
@@ -38,12 +38,13 @@ define(
|
||||
* @constructor
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function FixedController($scope, $q, dialogService, telemetrySubscriber, telemetryFormatter) {
|
||||
function FixedController($scope, $q, dialogService, telemetryHandler, telemetryFormatter, throttle) {
|
||||
var self = this,
|
||||
subscription,
|
||||
handle,
|
||||
names = {}, // Cache names by ID
|
||||
values = {}, // Cache values by ID
|
||||
elementProxiesById = {};
|
||||
elementProxiesById = {},
|
||||
maxDomainValue = Number.POSITIVE_INFINITY;
|
||||
|
||||
// Convert from element x/y/width/height to an
|
||||
// appropriate ng-style argument, to position elements.
|
||||
@@ -81,25 +82,52 @@ define(
|
||||
return element.handles().map(generateDragHandle);
|
||||
}
|
||||
|
||||
// Update the displayed value for this object
|
||||
function updateValue(telemetryObject) {
|
||||
var id = telemetryObject && telemetryObject.getId(),
|
||||
// Update the value displayed in elements of this telemetry object
|
||||
function setDisplayedValue(telemetryObject, value, alarm) {
|
||||
var id = telemetryObject.getId();
|
||||
(elementProxiesById[id] || []).forEach(function (element) {
|
||||
names[id] = telemetryObject.getModel().name;
|
||||
values[id] = telemetryFormatter.formatRangeValue(value);
|
||||
element.name = names[id];
|
||||
element.value = values[id];
|
||||
element.cssClass = alarm && alarm.cssClass;
|
||||
});
|
||||
}
|
||||
|
||||
// Update the displayed value for this object, from a specific
|
||||
// telemetry series
|
||||
function updateValueFromSeries(telemetryObject, telemetrySeries) {
|
||||
var index = telemetrySeries.getPointCount() - 1,
|
||||
limit = telemetryObject &&
|
||||
telemetryObject.getCapability('limit'),
|
||||
datum = telemetryObject &&
|
||||
subscription.getDatum(telemetryObject),
|
||||
alarm = limit && datum && limit.evaluate(datum);
|
||||
datum = telemetryObject && handle.getDatum(
|
||||
telemetryObject,
|
||||
index
|
||||
);
|
||||
|
||||
if (id) {
|
||||
(elementProxiesById[id] || []).forEach(function (element) {
|
||||
names[id] = telemetryObject.getModel().name;
|
||||
values[id] = telemetryFormatter.formatRangeValue(
|
||||
subscription.getRangeValue(telemetryObject)
|
||||
);
|
||||
element.name = names[id];
|
||||
element.value = values[id];
|
||||
element.cssClass = alarm && alarm.cssClass;
|
||||
});
|
||||
if (index >= 0) {
|
||||
setDisplayedValue(
|
||||
telemetryObject,
|
||||
telemetrySeries.getRangeValue(index),
|
||||
limit && datum && limit.evaluate(datum)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the displayed value for this object
|
||||
function updateValue(telemetryObject) {
|
||||
var limit = telemetryObject &&
|
||||
telemetryObject.getCapability('limit'),
|
||||
datum = telemetryObject &&
|
||||
handle.getDatum(telemetryObject);
|
||||
|
||||
if (telemetryObject &&
|
||||
(handle.getDomainValue(telemetryObject) < maxDomainValue)) {
|
||||
setDisplayedValue(
|
||||
telemetryObject,
|
||||
handle.getRangeValue(telemetryObject),
|
||||
limit && datum && limit.evaluate(datum)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +143,8 @@ define(
|
||||
|
||||
// Update telemetry values based on new data available
|
||||
function updateValues() {
|
||||
if (subscription) {
|
||||
subscription.getTelemetryObjects().forEach(updateValue);
|
||||
if (handle) {
|
||||
handle.getTelemetryObjects().forEach(updateValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,22 +206,29 @@ define(
|
||||
|
||||
// Free up subscription to telemetry
|
||||
function releaseSubscription() {
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscription = undefined;
|
||||
if (handle) {
|
||||
handle.unsubscribe();
|
||||
handle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe to telemetry updates for this domain object
|
||||
function subscribe(domainObject) {
|
||||
// Release existing subscription (if any)
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
if (handle) {
|
||||
handle.unsubscribe();
|
||||
}
|
||||
|
||||
// Make a new subscription
|
||||
subscription = domainObject &&
|
||||
telemetrySubscriber.subscribe(domainObject, updateValues);
|
||||
handle = domainObject && telemetryHandler.handle(
|
||||
domainObject,
|
||||
updateValues
|
||||
);
|
||||
// Request an initial historical telemetry value
|
||||
handle.request(
|
||||
{ size: 1 }, // Only need a single data point
|
||||
updateValueFromSeries
|
||||
);
|
||||
}
|
||||
|
||||
// Handle changes in the object's composition
|
||||
@@ -204,6 +239,17 @@ define(
|
||||
subscribe($scope.domainObject);
|
||||
}
|
||||
|
||||
// Trigger a new query for telemetry data
|
||||
function updateDisplayBounds(event, bounds) {
|
||||
maxDomainValue = bounds.end;
|
||||
if (handle) {
|
||||
handle.request(
|
||||
{ size: 1 }, // Only need a single data point
|
||||
updateValueFromSeries
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add an element to this view
|
||||
function addElement(element) {
|
||||
// Ensure that configuration field is populated
|
||||
@@ -278,6 +324,9 @@ define(
|
||||
|
||||
// Position panes where they are dropped
|
||||
$scope.$on("mctDrop", handleDrop);
|
||||
|
||||
// Respond to external bounds changes
|
||||
$scope.$on("telemetry:display:bounds", updateDisplayBounds);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,10 +30,10 @@ define(
|
||||
var mockScope,
|
||||
mockQ,
|
||||
mockDialogService,
|
||||
mockSubscriber,
|
||||
mockHandler,
|
||||
mockFormatter,
|
||||
mockDomainObject,
|
||||
mockSubscription,
|
||||
mockHandle,
|
||||
mockEvent,
|
||||
testGrid,
|
||||
testModel,
|
||||
@@ -78,9 +78,9 @@ define(
|
||||
'$scope',
|
||||
[ "$on", "$watch", "commit" ]
|
||||
);
|
||||
mockSubscriber = jasmine.createSpyObj(
|
||||
'telemetrySubscriber',
|
||||
[ 'subscribe' ]
|
||||
mockHandler = jasmine.createSpyObj(
|
||||
'telemetryHandler',
|
||||
[ 'handle' ]
|
||||
);
|
||||
mockQ = jasmine.createSpyObj('$q', ['when']);
|
||||
mockDialogService = jasmine.createSpyObj(
|
||||
@@ -95,9 +95,16 @@ define(
|
||||
'domainObject',
|
||||
[ 'getId', 'getModel', 'getCapability' ]
|
||||
);
|
||||
mockSubscription = jasmine.createSpyObj(
|
||||
mockHandle = jasmine.createSpyObj(
|
||||
'subscription',
|
||||
[ 'unsubscribe', 'getTelemetryObjects', 'getRangeValue', 'getDatum' ]
|
||||
[
|
||||
'unsubscribe',
|
||||
'getDomainValue',
|
||||
'getTelemetryObjects',
|
||||
'getRangeValue',
|
||||
'getDatum',
|
||||
'request'
|
||||
]
|
||||
);
|
||||
mockEvent = jasmine.createSpyObj(
|
||||
'event',
|
||||
@@ -116,13 +123,14 @@ define(
|
||||
{ type: "fixed.telemetry", id: 'c', x: 1, y: 1 }
|
||||
]};
|
||||
|
||||
mockSubscriber.subscribe.andReturn(mockSubscription);
|
||||
mockSubscription.getTelemetryObjects.andReturn(
|
||||
mockHandler.handle.andReturn(mockHandle);
|
||||
mockHandle.getTelemetryObjects.andReturn(
|
||||
testModel.composition.map(makeMockDomainObject)
|
||||
);
|
||||
mockSubscription.getRangeValue.andCallFake(function (o) {
|
||||
mockHandle.getRangeValue.andCallFake(function (o) {
|
||||
return testValues[o.getId()];
|
||||
});
|
||||
mockHandle.getDomainValue.andReturn(12321);
|
||||
mockFormatter.formatRangeValue.andCallFake(function (v) {
|
||||
return "Formatted " + v;
|
||||
});
|
||||
@@ -137,7 +145,7 @@ define(
|
||||
mockScope,
|
||||
mockQ,
|
||||
mockDialogService,
|
||||
mockSubscriber,
|
||||
mockHandler,
|
||||
mockFormatter
|
||||
);
|
||||
});
|
||||
@@ -145,7 +153,7 @@ define(
|
||||
it("subscribes when a domain object is available", function () {
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
findWatch("domainObject")(mockDomainObject);
|
||||
expect(mockSubscriber.subscribe).toHaveBeenCalledWith(
|
||||
expect(mockHandler.handle).toHaveBeenCalledWith(
|
||||
mockDomainObject,
|
||||
jasmine.any(Function)
|
||||
);
|
||||
@@ -156,13 +164,13 @@ define(
|
||||
|
||||
// First pass - should simply should subscribe
|
||||
findWatch("domainObject")(mockDomainObject);
|
||||
expect(mockSubscription.unsubscribe).not.toHaveBeenCalled();
|
||||
expect(mockSubscriber.subscribe.calls.length).toEqual(1);
|
||||
expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
|
||||
expect(mockHandler.handle.calls.length).toEqual(1);
|
||||
|
||||
// Object changes - should unsubscribe then resubscribe
|
||||
findWatch("domainObject")(mockDomainObject);
|
||||
expect(mockSubscription.unsubscribe).toHaveBeenCalled();
|
||||
expect(mockSubscriber.subscribe.calls.length).toEqual(2);
|
||||
expect(mockHandle.unsubscribe).toHaveBeenCalled();
|
||||
expect(mockHandler.handle.calls.length).toEqual(2);
|
||||
});
|
||||
|
||||
it("exposes visible elements based on configuration", function () {
|
||||
@@ -255,7 +263,7 @@ define(
|
||||
findWatch("model.composition")(mockScope.model.composition);
|
||||
|
||||
// Invoke the subscription callback
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
mockHandler.handle.mostRecentCall.args[1]();
|
||||
|
||||
// Get elements that controller is now exposing
|
||||
elements = controller.getElements();
|
||||
@@ -333,11 +341,11 @@ define(
|
||||
// Make an object available
|
||||
findWatch('domainObject')(mockDomainObject);
|
||||
// Also verify precondition
|
||||
expect(mockSubscription.unsubscribe).not.toHaveBeenCalled();
|
||||
expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
|
||||
// Destroy the scope
|
||||
findOn('$destroy')();
|
||||
// Should have unsubscribed
|
||||
expect(mockSubscription.unsubscribe).toHaveBeenCalled();
|
||||
expect(mockHandle.unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("exposes its grid size", function () {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"key": "example.page",
|
||||
"name": "Web Page",
|
||||
"glyph": "\u00EA",
|
||||
"description": "A component to display a web page or image with a valid URL. Can be added to a Display Layout.",
|
||||
"description": "Embed any web page or web-based image in a resizeable window component. Can be added to Display Layouts.",
|
||||
"features": [ "creation" ],
|
||||
"properties": [
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="abs l-iframe">
|
||||
<div class="l-iframe abs">
|
||||
<iframe ng-controller="EmbeddedPageController as ctl"
|
||||
ng-src="{{ctl.trust(model.url)}}">
|
||||
</iframe>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user