Compare commits
159 Commits
notebook-i
...
telemetry-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b939eb2fbe | ||
|
|
1afecdc82c | ||
|
|
b9cda6985e | ||
|
|
401b7e3f19 | ||
|
|
c9e9845172 | ||
|
|
abbba38eac | ||
|
|
db856251da | ||
|
|
e1566e448d | ||
|
|
d9aae0700c | ||
|
|
5c29726cc0 | ||
|
|
5c207c3fe0 | ||
|
|
eba1dd1a4e | ||
|
|
570edc0dec | ||
|
|
ad6bcd4ef8 | ||
|
|
aedbbbbf75 | ||
|
|
3caaf00483 | ||
|
|
971eda4d88 | ||
|
|
090d216517 | ||
|
|
d42d7ae68d | ||
|
|
68e6e3c121 | ||
|
|
7e7f39db2d | ||
|
|
b6e0fca828 | ||
|
|
ffc5896e5a | ||
|
|
fd6ebd152f | ||
|
|
7a5c1c0e1f | ||
|
|
2f7e1e3f1a | ||
|
|
d73746b51b | ||
|
|
2df54af019 | ||
|
|
586269f761 | ||
|
|
e536ab34d7 | ||
|
|
e15002dd72 | ||
|
|
453cf3ad6a | ||
|
|
5c46e48bde | ||
|
|
868ea9362f | ||
|
|
d69106ff2c | ||
|
|
1658b17c56 | ||
|
|
39cf0528ca | ||
|
|
3d12f7312b | ||
|
|
22481fdc31 | ||
|
|
4a9d27dc79 | ||
|
|
a5a9fefd40 | ||
|
|
dae4074934 | ||
|
|
a540a3573f | ||
|
|
4e7fe9082c | ||
|
|
568141bf81 | ||
|
|
ac3ea43fe5 | ||
|
|
e922e8d504 | ||
|
|
650a877d2a | ||
|
|
1202109c59 | ||
|
|
429d7bbd57 | ||
|
|
af749fe71b | ||
|
|
cf64c512ce | ||
|
|
14592d1c3e | ||
|
|
c5bd3da44a | ||
|
|
ff3e49e926 | ||
|
|
e244a3e431 | ||
|
|
c5d9fb6fd9 | ||
|
|
4c276ab422 | ||
|
|
bf321abae4 | ||
|
|
7336968ef9 | ||
|
|
d60956948b | ||
|
|
23d5c2e1ee | ||
|
|
2632b8891a | ||
|
|
fff4cd9d51 | ||
|
|
7f9fd5c705 | ||
|
|
be0291cf70 | ||
|
|
b3a6d7271d | ||
|
|
ebeed2f236 | ||
|
|
337c26c019 | ||
|
|
730f363f94 | ||
|
|
ae30e6110b | ||
|
|
6e4bf3e45b | ||
|
|
5465ca92f9 | ||
|
|
e55ea41b0a | ||
|
|
8cfb3cc689 | ||
|
|
2d728a1362 | ||
|
|
99333988df | ||
|
|
de783d4286 | ||
|
|
1e1a2443d5 | ||
|
|
d65e1e604e | ||
|
|
f6c1488ccd | ||
|
|
26be1ecf37 | ||
|
|
38f0f072bb | ||
|
|
e5e969665f | ||
|
|
ffbb662c99 | ||
|
|
bd7b23f896 | ||
|
|
c238def902 | ||
|
|
2d430ece7f | ||
|
|
c92644a661 | ||
|
|
41ce3c04f7 | ||
|
|
fcf77f359f | ||
|
|
40a2737915 | ||
|
|
216489d67f | ||
|
|
418a393b26 | ||
|
|
1f3d744494 | ||
|
|
ff3f2dccba | ||
|
|
e69973bd29 | ||
|
|
05b352cc36 | ||
|
|
9735548999 | ||
|
|
f9529b1362 | ||
|
|
c598cec702 | ||
|
|
e9ea1c4a0f | ||
|
|
e9238ff282 | ||
|
|
4cebd72cba | ||
|
|
f8a44d6e71 | ||
|
|
d0745b300b | ||
|
|
2a4e0a3081 | ||
|
|
1ff19f9574 | ||
|
|
7ef84cb50d | ||
|
|
cd05c70d64 | ||
|
|
568473b82f | ||
|
|
c61b074755 | ||
|
|
8ed66ab4ab | ||
|
|
b2502dd998 | ||
|
|
856eedbf9d | ||
|
|
0c0ca6e6af | ||
|
|
498b797e49 | ||
|
|
02c33388ba | ||
|
|
8a8e3cc055 | ||
|
|
36d60b16e9 | ||
|
|
de3114568b | ||
|
|
eb5835faeb | ||
|
|
ff1ddb0b79 | ||
|
|
15b127bb2e | ||
|
|
e4ed881f6d | ||
|
|
7b62cf130c | ||
|
|
72fd2e531c | ||
|
|
4a5392ef78 | ||
|
|
0150a708ca | ||
|
|
eacc181d5e | ||
|
|
405bb55881 | ||
|
|
4a35508459 | ||
|
|
98a9d71a2e | ||
|
|
a1596d0b06 | ||
|
|
4b3be4c483 | ||
|
|
0fa8472db1 | ||
|
|
e1e2dca1d8 | ||
|
|
755c013ec8 | ||
|
|
eab702b763 | ||
|
|
d15446ac91 | ||
|
|
500733afb2 | ||
|
|
2aa04b0a56 | ||
|
|
c051f342af | ||
|
|
8aeb365f5f | ||
|
|
827a28313d | ||
|
|
c83de8aad2 | ||
|
|
b55f43b8df | ||
|
|
8466723a90 | ||
|
|
a103b4dbff | ||
|
|
826ac3a947 | ||
|
|
597327f138 | ||
|
|
bef79402ca | ||
|
|
e68e0c381f | ||
|
|
c73f7259c2 | ||
|
|
4c9235ba10 | ||
|
|
55e2a77df8 | ||
|
|
cfbff02e7f | ||
|
|
54980fb296 | ||
|
|
ba98d9315c |
@@ -21,6 +21,5 @@
|
||||
"shadow": "outer",
|
||||
"strict": "implied",
|
||||
"undef": true,
|
||||
"unused": "vars",
|
||||
"latedef": "nofunc"
|
||||
"unused": "vars"
|
||||
}
|
||||
|
||||
15
API.md
15
API.md
@@ -879,21 +879,6 @@ openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
|
||||
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
|
||||
themes (dark and light) available for Open MCT. Note that at least one
|
||||
of these themes must be installed for Open MCT to appear correctly.
|
||||
* `openmct.plugins.URLIndicatorPlugin` adds an indicator which shows the
|
||||
availability of a URL with the following options:
|
||||
- `url` : URL to indicate the status of
|
||||
- `cssClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
|
||||
- `interval`: Interval between checking the connection, defaults to `10000`
|
||||
- `label` Name showing up as text in the status bar, defaults to url
|
||||
```javascript
|
||||
openmct.install(openmct.plugins.URLIndicatorPlugin({
|
||||
url: 'http://google.com',
|
||||
cssClass: 'check',
|
||||
interval: 10000,
|
||||
label: 'Google'
|
||||
})
|
||||
);
|
||||
```
|
||||
* `openmct.plugins.LocalStorage` provides persistence of user-created
|
||||
objects in browser-local storage. This is particularly useful in
|
||||
development environments.
|
||||
|
||||
@@ -88,7 +88,7 @@ and [`gulp`](http://gulpjs.com/).
|
||||
|
||||
To build Open MCT for deployment:
|
||||
|
||||
`npm run prepare`
|
||||
`npm run prepublish`
|
||||
|
||||
This will compile and minify JavaScript sources, as well as copy over assets.
|
||||
The contents of the `dist` folder will contain a runnable Open MCT
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
"screenfull": "^3.0.0",
|
||||
"node-uuid": "^1.4.7",
|
||||
"comma-separated-values": "^3.6.4",
|
||||
"file-saver": "^1.3.3",
|
||||
"zepto": "^1.1.6",
|
||||
"FileSaver.js": "^0.0.2",
|
||||
"zepto": "1.2.0",
|
||||
"eventemitter3": "^1.2.0",
|
||||
"lodash": "3.10.1",
|
||||
"almond": "~0.3.2",
|
||||
"html2canvas": "^0.4.1",
|
||||
"moment-timezone": "^0.5.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
circle.yml
16
circle.yml
@@ -1,17 +1,15 @@
|
||||
machine:
|
||||
node:
|
||||
version: 4.7.0
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- npm install -g npm@latest
|
||||
|
||||
deployment:
|
||||
production:
|
||||
branch: master
|
||||
commands:
|
||||
- npm install canvas nomnoml
|
||||
- ./build-docs.sh
|
||||
- git fetch --unshallow
|
||||
- git push git@heroku.com:openmctweb-demo.git $CIRCLE_SHA1:refs/heads/master
|
||||
openmct-demo:
|
||||
branch: live_demo
|
||||
heroku:
|
||||
appname: openmct-demo
|
||||
openmctweb-staging-deux:
|
||||
branch: mobile
|
||||
heroku:
|
||||
@@ -24,4 +22,4 @@ test:
|
||||
general:
|
||||
branches:
|
||||
ignore:
|
||||
- gh-pages
|
||||
- gh-pages
|
||||
|
||||
@@ -2283,7 +2283,7 @@ To install build dependencies (only needs to be run once):
|
||||
|
||||
To build:
|
||||
|
||||
`npm run prepare`
|
||||
`npm run prepublish`
|
||||
|
||||
This will compile and minify JavaScript sources, as well as copy over assets.
|
||||
The contents of the `dist` folder will contain a runnable Open MCT
|
||||
|
||||
@@ -44,7 +44,9 @@ define([
|
||||
message = message.data;
|
||||
var callback = this.callbacks[message.id];
|
||||
if (callback) {
|
||||
callback(message);
|
||||
if (callback(message)) {
|
||||
delete this.callbacks[message.id];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,7 +72,6 @@ define([
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
var messageId;
|
||||
|
||||
function callback(message) {
|
||||
if (message.error) {
|
||||
@@ -78,27 +79,33 @@ define([
|
||||
} else {
|
||||
deferred.resolve(message.data);
|
||||
}
|
||||
delete this.callbacks[messageId];
|
||||
return true;
|
||||
}
|
||||
|
||||
messageId = this.dispatch('request', request, callback.bind(this));
|
||||
this.dispatch('request', request, callback);
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
WorkerInterface.prototype.subscribe = function (request, cb) {
|
||||
function callback(message) {
|
||||
var isCancelled = false;
|
||||
|
||||
var callback = function (message) {
|
||||
if (isCancelled) {
|
||||
return true;
|
||||
}
|
||||
cb(message.data);
|
||||
};
|
||||
|
||||
var messageId = this.dispatch('subscribe', request, callback);
|
||||
var messageId = this.dispatch('subscribe', request, callback)
|
||||
|
||||
return function () {
|
||||
isCancelled = true;
|
||||
this.dispatch('unsubscribe', {
|
||||
id: messageId
|
||||
});
|
||||
delete this.callbacks[messageId];
|
||||
}.bind(this);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
/*global require,__dirname*/
|
||||
|
||||
require("v8-compile-cache");
|
||||
|
||||
var gulp = require('gulp'),
|
||||
sourcemaps = require('gulp-sourcemaps'),
|
||||
path = require('path'),
|
||||
@@ -179,4 +177,4 @@ gulp.task('install', [ 'assets', 'scripts' ]);
|
||||
|
||||
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
|
||||
|
||||
gulp.task('build', [ 'verify', 'install' ]);
|
||||
gulp.task('build', [ 'verify', 'install' ]);
|
||||
|
||||
@@ -43,9 +43,7 @@
|
||||
openmct.install(openmct.plugins.ExampleImagery());
|
||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||
openmct.install(openmct.plugins.ImportExport());
|
||||
openmct.install(openmct.plugins.AutoflowView({
|
||||
type: "telemetry.panel"
|
||||
}));
|
||||
openmct.install(openmct.plugins.TelemetryMean());
|
||||
openmct.install(openmct.plugins.Conductor({
|
||||
menuOptions: [
|
||||
{
|
||||
|
||||
@@ -36,8 +36,6 @@ module.exports = function(config) {
|
||||
files: [
|
||||
{pattern: 'bower_components/**/*.js', included: false},
|
||||
{pattern: 'node_modules/d3-*/**/*.js', included: false},
|
||||
{pattern: 'node_modules/vue/**/*.js', included: false},
|
||||
{pattern: 'node_modules/@cristian77/**/*.js', included: false},
|
||||
{pattern: 'src/**/*.js', included: false},
|
||||
{pattern: 'example/**/*.html', included: false},
|
||||
{pattern: 'example/**/*.js', included: false},
|
||||
|
||||
12
openmct.js
12
openmct.js
@@ -33,11 +33,10 @@ requirejs.config({
|
||||
"moment": "bower_components/moment/moment",
|
||||
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
|
||||
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
|
||||
"saveAs": "bower_components/file-saver/FileSaver.min",
|
||||
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
|
||||
"screenfull": "bower_components/screenfull/dist/screenfull.min",
|
||||
"text": "bower_components/text/text",
|
||||
"uuid": "bower_components/node-uuid/uuid",
|
||||
"vue": "node_modules/vue/dist/vue.min",
|
||||
"zepto": "bower_components/zepto/zepto.min",
|
||||
"lodash": "bower_components/lodash/lodash",
|
||||
"d3-selection": "node_modules/d3-selection/build/d3-selection.min",
|
||||
@@ -49,8 +48,7 @@ requirejs.config({
|
||||
"d3-format": "node_modules/d3-format/build/d3-format.min",
|
||||
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
|
||||
"d3-time": "node_modules/d3-time/build/d3-time.min",
|
||||
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
|
||||
"painterro": "node_modules/@cristian77/painterro/build/painterro.min"
|
||||
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min"
|
||||
},
|
||||
"shim": {
|
||||
"angular": {
|
||||
@@ -68,12 +66,6 @@ requirejs.config({
|
||||
"moment-duration-format": {
|
||||
"deps": ["moment"]
|
||||
},
|
||||
"painterro": {
|
||||
"exports": "Painterro"
|
||||
},
|
||||
"saveAs": {
|
||||
"exports": "saveAs"
|
||||
},
|
||||
"screenfull": {
|
||||
"exports": "screenfull"
|
||||
},
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"version": "0.12.1-SNAPSHOT",
|
||||
"description": "The Open MCT core platform",
|
||||
"dependencies": {
|
||||
"@cristian77/painterro": "^0.2.48",
|
||||
"d3-array": "^1.0.2",
|
||||
"d3-axis": "^1.0.4",
|
||||
"d3-collection": "^1.0.2",
|
||||
@@ -16,8 +15,7 @@
|
||||
"d3-time-format": "^2.0.3",
|
||||
"express": "^4.13.1",
|
||||
"minimist": "^1.1.1",
|
||||
"request": "^2.69.0",
|
||||
"vue": "^2.5.6"
|
||||
"request": "^2.69.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bower": "^1.7.7",
|
||||
@@ -51,8 +49,7 @@
|
||||
"moment": "^2.11.1",
|
||||
"node-bourbon": "^4.2.3",
|
||||
"requirejs": "2.1.x",
|
||||
"split": "^1.0.0",
|
||||
"v8-compile-cache": "^1.1.0"
|
||||
"split": "^1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node app.js",
|
||||
@@ -62,7 +59,7 @@
|
||||
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
||||
"otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
|
||||
"docs": "npm run jsdoc ; npm run otherdoc",
|
||||
"prepare": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
|
||||
"prepublish": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -57,12 +57,7 @@
|
||||
</div>
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs flex-elem grows object-holder-main scroll"
|
||||
mct-selectable="{
|
||||
item: domainObject.useCapability('adapter'),
|
||||
oldItem: domainObject
|
||||
}"
|
||||
mct-init-select>
|
||||
class="abs flex-elem grows object-holder-main scroll">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,21 +19,12 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-controller="InspectorController as controller">
|
||||
<div ng-controller="InspectorController">
|
||||
<div ng-repeat="region in regions">
|
||||
<mct-representation
|
||||
key="'object-properties'"
|
||||
mct-object="controller.selectedItem()"
|
||||
key="region.content.key"
|
||||
mct-object="domainObject"
|
||||
ng-model="ngModel">
|
||||
</mct-representation>
|
||||
|
||||
<div ng-if="!controller.hasProviderView()">
|
||||
<mct-representation
|
||||
key="inspectorKey"
|
||||
mct-object="controller.selectedItem()"
|
||||
ng-model="ngModel">
|
||||
</mct-representation>
|
||||
</div>
|
||||
|
||||
<div class='inspector-provider-view'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
ng-class="{ last:($index + 1) === contextualParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
@@ -49,6 +51,8 @@
|
||||
ng-class="{ last:($index + 1) === primaryParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
|
||||
@@ -42,37 +42,23 @@ define(
|
||||
* @param event the mouse event
|
||||
*/
|
||||
ObjectHeaderController.prototype.updateName = function (event) {
|
||||
if (!event || !event.currentTarget) {
|
||||
return;
|
||||
}
|
||||
if (event && (event.type === 'blur' || event.which === 13)) {
|
||||
var name = event.currentTarget.innerHTML;
|
||||
|
||||
if (event.type === 'blur') {
|
||||
this.updateModel(event);
|
||||
} else if (event.which === 13) {
|
||||
this.updateModel(event);
|
||||
event.currentTarget.blur();
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
};
|
||||
if (name.length === 0) {
|
||||
name = "Unnamed " + this.domainObject.getCapability("type").typeDef.name;
|
||||
event.currentTarget.innerHTML = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the model.
|
||||
*
|
||||
* @param event the mouse event
|
||||
* @param private
|
||||
*/
|
||||
ObjectHeaderController.prototype.updateModel = function (event) {
|
||||
var name = event.currentTarget.textContent.replace(/\n/g, ' ');
|
||||
if (name !== this.$scope.domainObject.model.name) {
|
||||
this.domainObject.getCapability('mutation').mutate(function (model) {
|
||||
model.name = name;
|
||||
});
|
||||
}
|
||||
|
||||
if (name.length === 0) {
|
||||
name = "Unnamed " + this.domainObject.getCapability("type").typeDef.name;
|
||||
event.currentTarget.textContent = name;
|
||||
}
|
||||
|
||||
if (name !== this.domainObject.getModel().name) {
|
||||
this.domainObject.getCapability('mutation').mutate(function (model) {
|
||||
model.name = name;
|
||||
});
|
||||
if (event.which === 13) {
|
||||
event.currentTarget.blur();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ define(
|
||||
mockTypeCapability,
|
||||
mockEvent,
|
||||
mockCurrentTarget,
|
||||
model,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
@@ -48,11 +47,8 @@ define(
|
||||
type: mockTypeCapability
|
||||
};
|
||||
|
||||
model = {
|
||||
name: "Test name"
|
||||
};
|
||||
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "getModel"]);
|
||||
mockDomainObject.getModel.andReturn(model);
|
||||
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "model"]);
|
||||
mockDomainObject.model = {name: "Test name"};
|
||||
mockDomainObject.getCapability.andCallFake(function (key) {
|
||||
return mockCapabilities[key];
|
||||
});
|
||||
@@ -61,7 +57,7 @@ define(
|
||||
domainObject: mockDomainObject
|
||||
};
|
||||
|
||||
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "textContent"]);
|
||||
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "innerHTML"]);
|
||||
mockCurrentTarget.blur.andReturn(mockCurrentTarget);
|
||||
|
||||
mockEvent = {
|
||||
@@ -75,7 +71,7 @@ define(
|
||||
|
||||
it("updates the model with new name on blur", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
mockCurrentTarget.innerHTML = "New name";
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||
@@ -83,23 +79,23 @@ define(
|
||||
|
||||
it("updates the model with a default for blank names", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = "";
|
||||
mockCurrentTarget.innerHTML = "";
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockCurrentTarget.textContent.length).not.toEqual(0);
|
||||
expect(mockCurrentTarget.innerHTML.length).not.toEqual(0);
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not update the model if the same name", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = mockDomainObject.getModel().name;
|
||||
mockCurrentTarget.innerHTML = mockDomainObject.model.name;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("updates the model on enter keypress event only", function () {
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
mockCurrentTarget.innerHTML = "New name";
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
@@ -109,13 +105,12 @@ define(
|
||||
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
|
||||
mockMutationCapability.mutate.mostRecentCall.args[0](model);
|
||||
mockMutationCapability.mutate.mostRecentCall.args[0](mockDomainObject.model);
|
||||
|
||||
expect(mockDomainObject.getModel().name).toBe("New name");
|
||||
expect(mockDomainObject.model.name).toBe("New name");
|
||||
});
|
||||
|
||||
it("blurs the field on enter key press", function () {
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
mockEvent.which = 13;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
|
||||
@@ -121,8 +121,7 @@ define([
|
||||
"key": "ElementsController",
|
||||
"implementation": ElementsController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"openmct"
|
||||
"$scope"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -300,6 +299,9 @@ define([
|
||||
{
|
||||
"key": "edit-elements",
|
||||
"template": elementsTemplate,
|
||||
"uses": [
|
||||
"composition"
|
||||
],
|
||||
"gestures": [
|
||||
"drop"
|
||||
]
|
||||
@@ -383,10 +385,7 @@ define([
|
||||
]
|
||||
},
|
||||
{
|
||||
"implementation": EditToolbarRepresenter,
|
||||
"depends": [
|
||||
"openmct"
|
||||
]
|
||||
"implementation": EditToolbarRepresenter
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
|
||||
@@ -61,12 +61,7 @@
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs flex-elem grows object-holder-main scroll"
|
||||
toolbar="toolbar"
|
||||
mct-selectable="{
|
||||
item: domainObject.useCapability('adapter'),
|
||||
oldItem: domainObject
|
||||
}"
|
||||
mct-init-select>
|
||||
toolbar="toolbar">
|
||||
</mct-representation>
|
||||
</div><!--/ l-object-wrapper-inner -->
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
ng-model="filterBy">
|
||||
</mct-include>
|
||||
<div class="flex-elem grows vscroll">
|
||||
<ul class="tree" ng-if="composition.length > 0">
|
||||
<ul class="tree">
|
||||
<li ng-repeat="containedObject in composition | filter:searchElements">
|
||||
<span class="tree-item">
|
||||
<mct-representation
|
||||
@@ -36,6 +36,5 @@
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-if="composition.length === 0">No contained elements</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,15 +101,10 @@ define(
|
||||
*/
|
||||
EditorCapability.prototype.finish = function () {
|
||||
var domainObject = this.domainObject;
|
||||
|
||||
if (this.transactionService.isActive()) {
|
||||
return this.transactionService.cancel().then(function () {
|
||||
domainObject.getCapability("status").set("editing", false);
|
||||
return domainObject;
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(domainObject);
|
||||
}
|
||||
return this.transactionService.cancel().then(function () {
|
||||
domainObject.getCapability("status").set("editing", false);
|
||||
return domainObject;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,16 @@ define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
function isDirty(domainObject) {
|
||||
var navigatedObject = domainObject,
|
||||
editorCapability = navigatedObject &&
|
||||
navigatedObject.getCapability("editor");
|
||||
|
||||
return editorCapability &&
|
||||
editorCapability.isEditContextRoot() &&
|
||||
editorCapability.dirty();
|
||||
}
|
||||
|
||||
function cancelEditing(domainObject) {
|
||||
var navigatedObject = domainObject,
|
||||
editorCapability = navigatedObject &&
|
||||
@@ -49,7 +59,10 @@ define(
|
||||
|
||||
var removeCheck = navigationService
|
||||
.checkBeforeNavigation(function () {
|
||||
return "Continuing will cause the loss of any unsaved changes.";
|
||||
if (isDirty(domainObject)) {
|
||||
return "Continuing will cause the loss of any unsaved changes.";
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
|
||||
@@ -29,11 +29,7 @@ define(
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ElementsController($scope, openmct) {
|
||||
this.scope = $scope;
|
||||
this.scope.composition = [];
|
||||
var self = this;
|
||||
|
||||
function ElementsController($scope) {
|
||||
function filterBy(text) {
|
||||
if (typeof text === 'undefined') {
|
||||
return $scope.searchText;
|
||||
@@ -51,45 +47,10 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
function setSelection(selection) {
|
||||
self.scope.selection = selection;
|
||||
self.refreshComposition(selection);
|
||||
}
|
||||
|
||||
$scope.filterBy = filterBy;
|
||||
$scope.searchElements = searchElements;
|
||||
|
||||
openmct.selection.on('change', setSelection);
|
||||
setSelection(openmct.selection.get());
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
openmct.selection.off("change", setSelection);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the composition for the selected object and populates the scope with it.
|
||||
*
|
||||
* @param selection the selection object
|
||||
* @private
|
||||
*/
|
||||
ElementsController.prototype.refreshComposition = function (selection) {
|
||||
if (!selection[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selected = selection[0].context.oldItem;
|
||||
var selectedObjectComposition = selected && selected.useCapability('composition');
|
||||
|
||||
if (selectedObjectComposition) {
|
||||
selectedObjectComposition.then(function (composition) {
|
||||
this.scope.composition = composition;
|
||||
}.bind(this));
|
||||
} else {
|
||||
this.scope.composition = [];
|
||||
}
|
||||
};
|
||||
|
||||
return ElementsController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -80,6 +80,12 @@ define(
|
||||
return closeEditor();
|
||||
}
|
||||
|
||||
function resolveWith (object) {
|
||||
return function () {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
newModel.type = this.type.getKey();
|
||||
newModel.location = this.parent.getId();
|
||||
newObject = this.parent.useCapability('instantiation', newModel);
|
||||
|
||||
@@ -38,7 +38,7 @@ define(
|
||||
* @constructor
|
||||
* @implements {Representer}
|
||||
*/
|
||||
function EditToolbarRepresenter(openmct, scope, element, attrs) {
|
||||
function EditToolbarRepresenter(scope, element, attrs) {
|
||||
var self = this;
|
||||
|
||||
// Mark changes as ready to persist
|
||||
@@ -109,7 +109,6 @@ define(
|
||||
this.updateSelection = updateSelection;
|
||||
this.toolbar = undefined;
|
||||
this.toolbarObject = {};
|
||||
this.openmct = openmct;
|
||||
|
||||
// If this representation exposes a toolbar, set up watches
|
||||
// to synchronize with it.
|
||||
@@ -147,7 +146,7 @@ define(
|
||||
// Expose the toolbar object to the parent scope
|
||||
initialize(definition);
|
||||
// Create a selection scope
|
||||
this.setSelection(new EditToolbarSelection(this.openmct));
|
||||
this.setSelection(new EditToolbarSelection());
|
||||
// Initialize toolbar to an empty selection
|
||||
this.updateSelection([]);
|
||||
};
|
||||
|
||||
@@ -38,24 +38,10 @@ define(
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditToolbarSelection(openmct) {
|
||||
function EditToolbarSelection() {
|
||||
this.selection = [{}];
|
||||
this.selecting = false;
|
||||
this.selectedObj = undefined;
|
||||
|
||||
openmct.selection.on('change', function (selection) {
|
||||
var selected = selection[0];
|
||||
|
||||
if (selected && selected.context.toolbar) {
|
||||
this.select(selected.context.toolbar);
|
||||
} else {
|
||||
this.deselect();
|
||||
}
|
||||
|
||||
if (selected && selected.context.viewProxy) {
|
||||
this.proxy(selected.context.viewProxy);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,7 +62,6 @@ define(
|
||||
);
|
||||
mockTransactionService.commit.andReturn(fastPromise());
|
||||
mockTransactionService.cancel.andReturn(fastPromise());
|
||||
mockTransactionService.isActive = jasmine.createSpy('isActive');
|
||||
|
||||
mockStatusCapability = jasmine.createSpyObj(
|
||||
"statusCapability",
|
||||
@@ -142,7 +141,6 @@ define(
|
||||
|
||||
describe("finish", function () {
|
||||
beforeEach(function () {
|
||||
mockTransactionService.isActive.andReturn(true);
|
||||
capability.edit();
|
||||
capability.finish();
|
||||
});
|
||||
@@ -154,23 +152,6 @@ define(
|
||||
});
|
||||
});
|
||||
|
||||
describe("finish", function () {
|
||||
beforeEach(function () {
|
||||
mockTransactionService.isActive.andReturn(false);
|
||||
capability.edit();
|
||||
});
|
||||
|
||||
it("does not cancel transaction when transaction is not active", function () {
|
||||
capability.finish();
|
||||
expect(mockTransactionService.cancel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns a promise", function () {
|
||||
expect(capability.finish() instanceof Promise).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("dirty", function () {
|
||||
var model = {};
|
||||
|
||||
|
||||
@@ -104,10 +104,10 @@ define(
|
||||
mockEditorCapability.isEditContextRoot.andReturn(false);
|
||||
mockEditorCapability.dirty.andReturn(false);
|
||||
|
||||
expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
|
||||
expect(checkFn()).toBe(false);
|
||||
|
||||
mockEditorCapability.isEditContextRoot.andReturn(true);
|
||||
expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
|
||||
expect(checkFn()).toBe(false);
|
||||
|
||||
mockEditorCapability.dirty.andReturn(true);
|
||||
expect(checkFn())
|
||||
|
||||
@@ -27,23 +27,11 @@ define(
|
||||
|
||||
describe("The Elements Pane controller", function () {
|
||||
var mockScope,
|
||||
mockOpenMCT,
|
||||
mockSelection,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", ['$on']);
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn([]);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection
|
||||
};
|
||||
|
||||
controller = new ElementsController(mockScope, mockOpenMCT);
|
||||
mockScope = jasmine.createSpy("$scope");
|
||||
controller = new ElementsController(mockScope);
|
||||
});
|
||||
|
||||
function getModel(model) {
|
||||
|
||||
@@ -29,9 +29,7 @@ define(
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockUnwatch,
|
||||
representer,
|
||||
mockOpenMCT,
|
||||
mockSelection;
|
||||
representer;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
@@ -48,18 +46,7 @@ define(
|
||||
|
||||
mockScope.$parent.$watchCollection.andReturn(mockUnwatch);
|
||||
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn([]);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection
|
||||
};
|
||||
|
||||
representer = new EditToolbarRepresenter(
|
||||
mockOpenMCT,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs
|
||||
|
||||
@@ -28,25 +28,13 @@ define(
|
||||
var testProxy,
|
||||
testElement,
|
||||
otherElement,
|
||||
selection,
|
||||
mockSelection,
|
||||
mockOpenMCT;
|
||||
selection;
|
||||
|
||||
beforeEach(function () {
|
||||
testProxy = { someKey: "some value" };
|
||||
testElement = { someOtherKey: "some other value" };
|
||||
otherElement = { yetAnotherKey: 42 };
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
// 'select',
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn([]);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection
|
||||
};
|
||||
selection = new EditToolbarSelection(mockOpenMCT);
|
||||
selection = new EditToolbarSelection();
|
||||
selection.proxy(testProxy);
|
||||
});
|
||||
|
||||
|
||||
@@ -121,9 +121,6 @@ define([
|
||||
};
|
||||
|
||||
UTCTimeFormat.prototype.parse = function (text) {
|
||||
if (typeof text === 'number') {
|
||||
return text;
|
||||
}
|
||||
return moment.utc(text, DATE_FORMATS).valueOf();
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ define([
|
||||
"./src/controllers/BannerController",
|
||||
"./src/directives/MCTContainer",
|
||||
"./src/directives/MCTDrag",
|
||||
"./src/directives/MCTSelectable",
|
||||
"./src/directives/MCTClickElsewhere",
|
||||
"./src/directives/MCTResize",
|
||||
"./src/directives/MCTPopup",
|
||||
@@ -91,7 +90,6 @@ define([
|
||||
BannerController,
|
||||
MCTContainer,
|
||||
MCTDrag,
|
||||
MCTSelectable,
|
||||
MCTClickElsewhere,
|
||||
MCTResize,
|
||||
MCTPopup,
|
||||
@@ -330,13 +328,6 @@ define([
|
||||
"$document"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "mctSelectable",
|
||||
"implementation": MCTSelectable,
|
||||
"depends": [
|
||||
"openmct"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "mctClickElsewhere",
|
||||
"implementation": MCTClickElsewhere,
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
}
|
||||
|
||||
.l-fixed-position-item {
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
&.s-not-selected {
|
||||
opacity: 0.8;
|
||||
|
||||
@@ -290,11 +290,6 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.l-rule-action-buttons-wrapper {
|
||||
.t-delete {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.t-condition {
|
||||
&:hover {
|
||||
.l-condition-action-buttons-wrapper {
|
||||
|
||||
@@ -80,32 +80,23 @@
|
||||
|
||||
// Editing Grids
|
||||
.l-grid-holder {
|
||||
display: block;
|
||||
.l-grid {
|
||||
&.l-grid-x { @include bgTicks($colorGridLines, 'x'); }
|
||||
&.l-grid-y { @include bgTicks($colorGridLines, 'y'); }
|
||||
}
|
||||
}
|
||||
|
||||
// Display grid when selected or selection parent.
|
||||
.s-selected .l-grid-holder,
|
||||
.s-selected-parent .l-grid-holder {
|
||||
display: block;
|
||||
// Prevent nested frames from showing their grids
|
||||
.t-frame-outer .l-grid-holder { display: none !important; }
|
||||
|
||||
// Prevent nested elements from showing s-hover-border
|
||||
.t-frame-outer .s-hover-border {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
// Display in nested frames...
|
||||
.t-frame-outer {
|
||||
// ...when drilled in or selection parent...
|
||||
&.s-drilled-in, &.s-selected-parent {
|
||||
.l-grid-holder {
|
||||
display: block;
|
||||
}
|
||||
.t-frame-outer:not(.s-drilled-in) .l-grid-holder {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// ...but hide otherwise.
|
||||
.l-grid-holder {
|
||||
display: none;
|
||||
}
|
||||
// Prevent nested frames from being selectable until we have proper sub-object editing
|
||||
.t-frame-outer .t-frame-outer {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
z-index: 0; // Needed to prevent child-frame controls from showing through when another child-frame is above
|
||||
&:not(.no-frame) {
|
||||
background: $colorBodyBg;
|
||||
border-color: $bc;
|
||||
border: 1px solid $bc;
|
||||
&:hover {
|
||||
border-color: lighten($bc, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.object-browse-bar {
|
||||
font-size: 0.75em;
|
||||
height: $ohH;
|
||||
@@ -43,7 +45,9 @@
|
||||
&.t-object-type-timer,
|
||||
&.t-object-type-clock,
|
||||
&.t-object-type-hyperlink,
|
||||
&.t-object-type-summary-widget {
|
||||
&.t-object-type-summary-widget,
|
||||
&.no-frame .t-object-type-fixed-display,
|
||||
&.no-frame .t-object-type-layout {
|
||||
// Hide the right side buttons for objects where they don't make sense
|
||||
// Note that this will hide the view Switcher button if applied
|
||||
// to an object that has it.
|
||||
@@ -90,9 +94,9 @@
|
||||
|
||||
&.no-frame {
|
||||
background: transparent !important;
|
||||
border-color: transparent;
|
||||
border: none !important;
|
||||
.object-browse-bar .right {
|
||||
$m: 0;
|
||||
$m: 0; // $interiorMarginSm;
|
||||
background: rgba(black, 0.3);
|
||||
border-radius: $basicCr;
|
||||
padding: $interiorMarginSm;
|
||||
@@ -113,7 +117,6 @@
|
||||
display: none;
|
||||
}
|
||||
> .object-holder.abs {
|
||||
overflow: hidden;
|
||||
top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,52 +20,35 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.s-hover-border {
|
||||
border: 1px solid transparent;
|
||||
&:hover {
|
||||
border-color: rgba($colorSelectableSelectedPrimary, 0.5) !important;
|
||||
}
|
||||
border: none;
|
||||
}
|
||||
|
||||
.s-status-editing {
|
||||
// Limit to editing mode
|
||||
$o: 0.5;
|
||||
$oHover: 0.8;
|
||||
$bc: $colorSelectableSelectedPrimary;
|
||||
// Limit to editing mode until we have sub-object selection
|
||||
.s-hover-border {
|
||||
// Show a border by default so user can see object bounds and empty objects
|
||||
border-color: rgba($bc, $o) !important;
|
||||
border-style: dotted !important;
|
||||
|
||||
border: 1px dotted rgba($colorSelectableSelectedPrimary, 0.3) !important;
|
||||
&:hover {
|
||||
border-color: rgba($bc, $oHover) !important;
|
||||
}
|
||||
|
||||
&.t-object-type-layout {
|
||||
border-style: dashed !important;
|
||||
border-color: rgba($colorSelectableSelectedPrimary, 0.7) !important;
|
||||
}
|
||||
}
|
||||
.s-selected {
|
||||
&.s-moveable {
|
||||
&:not(.s-drilled-in) {
|
||||
cursor: move;
|
||||
|
||||
.s-selected > .s-hover-border,
|
||||
.s-selected.s-hover-border {
|
||||
// Styles for a selected object. Also used by legacy Fixed Position/Panel objects.
|
||||
border-color: $colorSelectableSelectedPrimary !important;
|
||||
@include boxShdwLarge();
|
||||
// Show edit-corners if you got 'em
|
||||
.edit-corner {
|
||||
display: block;
|
||||
&:hover {
|
||||
background-color: rgba($colorKey, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.s-selected > .s-hover-border,
|
||||
.s-selected.s-hover-border {
|
||||
// Styles for a selected object. Also used by legacy Fixed Position/Panel objects.
|
||||
border-color: $colorSelectableSelectedPrimary !important;
|
||||
@include boxShdwLarge();
|
||||
// Show edit-corners if you got 'em
|
||||
.edit-corner {
|
||||
display: block;
|
||||
&:hover {
|
||||
background-color: rgba($colorKey, 1);
|
||||
}
|
||||
.s-selected > .s-moveable,
|
||||
.s-selected.s-moveable {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span ng-controller="DateTimeFieldController">
|
||||
<input type="text" autocorrect="off" spellcheck="false"
|
||||
<input type="text"
|
||||
ng-model="textValue"
|
||||
ng-blur="restoreTextValue(); ngBlur()"
|
||||
ng-mouseup="ngMouseup()"
|
||||
|
||||
@@ -40,7 +40,7 @@ define(
|
||||
|
||||
// Gets an array of the contextual parents/ancestors of the selected object
|
||||
function getContextualPath() {
|
||||
var currentObj = $scope.domainObject,
|
||||
var currentObj = $scope.ngModel.selectedObject,
|
||||
currentParent,
|
||||
parents = [];
|
||||
|
||||
@@ -68,7 +68,7 @@ define(
|
||||
|
||||
// If this the the initial call of this recursive function
|
||||
if (!current) {
|
||||
current = $scope.domainObject;
|
||||
current = $scope.ngModel.selectedObject;
|
||||
$scope.primaryParents = [];
|
||||
}
|
||||
|
||||
@@ -87,16 +87,16 @@ define(
|
||||
|
||||
// Gets the metadata for the selected object
|
||||
function getMetadata() {
|
||||
$scope.metadata = $scope.domainObject &&
|
||||
$scope.domainObject.hasCapability('metadata') &&
|
||||
$scope.domainObject.useCapability('metadata');
|
||||
$scope.metadata = $scope.ngModel.selectedObject &&
|
||||
$scope.ngModel.selectedObject.hasCapability('metadata') &&
|
||||
$scope.ngModel.selectedObject.useCapability('metadata');
|
||||
}
|
||||
|
||||
// Set scope variables when the selected object changes
|
||||
$scope.$watch('domainObject', function () {
|
||||
$scope.isLink = $scope.domainObject &&
|
||||
$scope.domainObject.hasCapability('location') &&
|
||||
$scope.domainObject.getCapability('location').isLink();
|
||||
$scope.$watch('ngModel.selectedObject', function () {
|
||||
$scope.isLink = $scope.ngModel.selectedObject &&
|
||||
$scope.ngModel.selectedObject.hasCapability('location') &&
|
||||
$scope.ngModel.selectedObject.getCapability('location').isLink();
|
||||
|
||||
if ($scope.isLink) {
|
||||
getPrimaryPath();
|
||||
@@ -109,7 +109,7 @@ define(
|
||||
getMetadata();
|
||||
});
|
||||
|
||||
var mutation = $scope.domainObject.getCapability('mutation');
|
||||
var mutation = $scope.ngModel.selectedObject.getCapability('mutation');
|
||||
var unlisten = mutation.listen(getMetadata);
|
||||
$scope.$on('$destroy', unlisten);
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* The mct-selectable directive allows selection functionality
|
||||
* (click) to be attached to specific elements.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function MCTSelectable(openmct) {
|
||||
|
||||
// Link; install event handlers.
|
||||
function link(scope, element, attrs) {
|
||||
var removeSelectable = openmct.selection.selectable(
|
||||
element[0],
|
||||
scope.$eval(attrs.mctSelectable),
|
||||
attrs.hasOwnProperty('mctInitSelect') && scope.$eval(attrs.mctInitSelect) !== false
|
||||
);
|
||||
|
||||
scope.$on("$destroy", function () {
|
||||
removeSelectable();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// mct-selectable only makes sense as an attribute
|
||||
restrict: "A",
|
||||
// Link function, to install event handlers
|
||||
link: link
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return MCTSelectable;
|
||||
}
|
||||
);
|
||||
@@ -41,6 +41,16 @@ define(
|
||||
"$scope",
|
||||
["$watch", "$on"]
|
||||
);
|
||||
mockScope.ngModel = {};
|
||||
mockScope.ngModel.selectedObject = {
|
||||
getCapability: function () {
|
||||
return {
|
||||
listen: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
mockObjectService = jasmine.createSpyObj(
|
||||
"objectService",
|
||||
@@ -67,27 +77,22 @@ define(
|
||||
"location capability",
|
||||
["isLink"]
|
||||
);
|
||||
|
||||
mockDomainObject.getCapability.andCallFake(function (param) {
|
||||
if (param === 'location') {
|
||||
return mockLocationCapability;
|
||||
} else if (param === 'context') {
|
||||
return mockContextCapability;
|
||||
} else if (param === 'mutation') {
|
||||
return {
|
||||
listen: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
controller = new ObjectInspectorController(mockScope, mockObjectService);
|
||||
|
||||
// Change the selected object to trigger the watch call
|
||||
mockScope.ngModel.selectedObject = mockDomainObject;
|
||||
});
|
||||
|
||||
it("watches for changes to the selected object", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith('domainObject', jasmine.any(Function));
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith('ngModel.selectedObject', jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("looks for contextual parent objects", function () {
|
||||
|
||||
@@ -65,10 +65,6 @@ define(
|
||||
options = Object.create(OPTIONS);
|
||||
options.marginX = -bubbleSpaceLR;
|
||||
|
||||
// prevent bubble from appearing right under pointer,
|
||||
// which causes hover callback to be called multiple times
|
||||
options.offsetX = 1;
|
||||
|
||||
// On a phone, bubble takes up more screen real estate,
|
||||
// so position it differently (toward the bottom)
|
||||
if (this.agentService.isPhone()) {
|
||||
|
||||
@@ -38,8 +38,7 @@ define([
|
||||
"implementation": InspectorController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"openmct",
|
||||
"$document"
|
||||
"policyService"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -21,73 +21,44 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
['../../browse/src/InspectorRegion'],
|
||||
function (InspectorRegion) {
|
||||
|
||||
/**
|
||||
* The InspectorController listens for the selection changes and adds the selection
|
||||
* object to the scope.
|
||||
* The InspectorController adds region data for a domain object's type
|
||||
* to the scope.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function InspectorController($scope, openmct, $document) {
|
||||
var self = this;
|
||||
self.$scope = $scope;
|
||||
function InspectorController($scope, policyService) {
|
||||
var domainObject = $scope.domainObject,
|
||||
typeCapability = domainObject.getCapability('type'),
|
||||
statusListener;
|
||||
|
||||
/**
|
||||
* Callback handler for the selection change event.
|
||||
* Adds the selection object to the scope. If the selected item has an inspector view,
|
||||
* it puts the key in the scope. If provider view exists, it shows the view.
|
||||
* Filters region parts to only those allowed by region policies
|
||||
* @param regions
|
||||
* @returns {{}}
|
||||
*/
|
||||
function setSelection(selection) {
|
||||
if (selection[0]) {
|
||||
var view = openmct.inspectorViews.get(selection);
|
||||
var container = $document[0].querySelectorAll('.inspector-provider-view')[0];
|
||||
container.innerHTML = "";
|
||||
|
||||
if (view) {
|
||||
self.providerView = true;
|
||||
view.show(container);
|
||||
} else {
|
||||
self.providerView = false;
|
||||
var selectedItem = selection[0].context.oldItem;
|
||||
|
||||
if (selectedItem) {
|
||||
$scope.inspectorKey = selectedItem.getCapability("type").typeDef.inspector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.$scope.selection = selection;
|
||||
function filterRegions(inspector) {
|
||||
//Dupe so we're not modifying the type definition.
|
||||
return inspector.regions && inspector.regions.filter(function (region) {
|
||||
return policyService.allow('region', region, domainObject);
|
||||
});
|
||||
}
|
||||
|
||||
openmct.selection.on("change", setSelection);
|
||||
|
||||
setSelection(openmct.selection.get());
|
||||
function setRegions() {
|
||||
$scope.regions = filterRegions(typeCapability.getDefinition().inspector || new InspectorRegion());
|
||||
}
|
||||
|
||||
statusListener = domainObject.getCapability("status").listen(setRegions);
|
||||
$scope.$on("$destroy", function () {
|
||||
openmct.selection.off("change", setSelection);
|
||||
statusListener();
|
||||
});
|
||||
|
||||
setRegions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selected item.
|
||||
*
|
||||
* @returns a domain object
|
||||
*/
|
||||
InspectorController.prototype.selectedItem = function () {
|
||||
return this.$scope.selection[0].context.oldItem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a provider view exists.
|
||||
*
|
||||
* @returns 'true' if provider view exists, 'false' otherwise
|
||||
*/
|
||||
InspectorController.prototype.hasProviderView = function () {
|
||||
return this.providerView;
|
||||
};
|
||||
|
||||
return InspectorController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -27,93 +27,82 @@ define(
|
||||
describe("The inspector controller ", function () {
|
||||
var mockScope,
|
||||
mockDomainObject,
|
||||
mockOpenMCT,
|
||||
mockSelection,
|
||||
mockInspectorViews,
|
||||
mockTypeDef,
|
||||
controller,
|
||||
container,
|
||||
$document = [],
|
||||
selectable = [];
|
||||
mockTypeCapability,
|
||||
mockTypeDefinition,
|
||||
mockPolicyService,
|
||||
mockStatusCapability,
|
||||
capabilities = {},
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTypeDef = {
|
||||
typeDef: {
|
||||
inspector: "some-key"
|
||||
}
|
||||
mockTypeDefinition = {
|
||||
inspector:
|
||||
{
|
||||
'regions': [
|
||||
{'name': 'Part One'},
|
||||
{'name': 'Part Two'}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
mockTypeCapability = jasmine.createSpyObj('typeCapability', [
|
||||
'getDefinition'
|
||||
]);
|
||||
mockTypeCapability.getDefinition.andReturn(mockTypeDefinition);
|
||||
capabilities.type = mockTypeCapability;
|
||||
|
||||
mockStatusCapability = jasmine.createSpyObj('statusCapability', [
|
||||
'listen'
|
||||
]);
|
||||
capabilities.status = mockStatusCapability;
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj('domainObject', [
|
||||
'getCapability'
|
||||
]);
|
||||
mockDomainObject.getCapability.andReturn(mockTypeDef);
|
||||
mockDomainObject.getCapability.andCallFake(function (name) {
|
||||
return capabilities[name];
|
||||
});
|
||||
|
||||
mockPolicyService = jasmine.createSpyObj('policyService', [
|
||||
'allow'
|
||||
]);
|
||||
|
||||
mockScope = jasmine.createSpyObj('$scope',
|
||||
['$on', 'selection']
|
||||
['$on']
|
||||
);
|
||||
|
||||
selectable[0] = {
|
||||
context: {
|
||||
oldItem: mockDomainObject
|
||||
}
|
||||
};
|
||||
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn(selectable);
|
||||
|
||||
mockInspectorViews = jasmine.createSpyObj('inspectorViews', ['get']);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection,
|
||||
inspectorViews: mockInspectorViews
|
||||
};
|
||||
|
||||
container = jasmine.createSpy('container', ['innerHTML']);
|
||||
$document[0] = jasmine.createSpyObj("$document", ['querySelectorAll']);
|
||||
$document[0].querySelectorAll.andReturn([container]);
|
||||
|
||||
controller = new InspectorController(mockScope, mockOpenMCT, $document);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
});
|
||||
|
||||
it("listens for selection change event", function () {
|
||||
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
expect(controller.selectedItem()).toEqual(mockDomainObject);
|
||||
|
||||
var mockItem = jasmine.createSpyObj('domainObject', [
|
||||
'getCapability'
|
||||
]);
|
||||
mockItem.getCapability.andReturn(mockTypeDef);
|
||||
selectable[0].context.oldItem = mockItem;
|
||||
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
|
||||
expect(controller.selectedItem()).toEqual(mockItem);
|
||||
it("filters out regions disallowed by region policy", function () {
|
||||
mockPolicyService.allow.andReturn(false);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.regions.length).toBe(0);
|
||||
});
|
||||
|
||||
it("cleans up on scope destroy", function () {
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
'$destroy',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
mockScope.$on.calls[0].args[1]();
|
||||
|
||||
expect(mockOpenMCT.selection.off).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
it("does not filter out regions allowed by region policy", function () {
|
||||
mockPolicyService.allow.andReturn(true);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.regions.length).toBe(2);
|
||||
});
|
||||
|
||||
it("adds selection object to scope", function () {
|
||||
expect(mockScope.selection).toEqual(selectable);
|
||||
expect(controller.selectedItem()).toEqual(mockDomainObject);
|
||||
it("Responds to status changes", function () {
|
||||
mockPolicyService.allow.andReturn(true);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.regions.length).toBe(2);
|
||||
expect(mockStatusCapability.listen).toHaveBeenCalled();
|
||||
mockPolicyService.allow.andReturn(false);
|
||||
mockStatusCapability.listen.mostRecentCall.args[0]();
|
||||
expect(mockScope.regions.length).toBe(0);
|
||||
});
|
||||
|
||||
it("Unregisters status listener", function () {
|
||||
var mockListener = jasmine.createSpy('listener');
|
||||
mockStatusCapability.listen.andReturn(mockListener);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.$on).toHaveBeenCalledWith("$destroy", jasmine.any(Function));
|
||||
mockScope.$on.mostRecentCall.args[1]();
|
||||
expect(mockListener).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
54
platform/features/autoflow/plugin.js
Executable file
54
platform/features/autoflow/plugin.js
Executable file
@@ -0,0 +1,54 @@
|
||||
define([
|
||||
'text!./res/templates/autoflow-tabular.html',
|
||||
'./src/AutoflowTabularController',
|
||||
'./src/MCTAutoflowTable'
|
||||
], function (
|
||||
autoflowTabularTemplate,
|
||||
AutoflowTabularController,
|
||||
MCTAutoflowTable
|
||||
) {
|
||||
return function (options) {
|
||||
return function (openmct) {
|
||||
openmct.legacyRegistry.register("platform/features/autoflow", {
|
||||
"name": "WARP Telemetry Adapter",
|
||||
"description": "Retrieves telemetry from the WARP Server and provides related types and views.",
|
||||
"resources": "res",
|
||||
"extensions": {
|
||||
"views": [
|
||||
{
|
||||
"key": "autoflow",
|
||||
"name": "Autoflow Tabular",
|
||||
"cssClass": "icon-packet",
|
||||
"description": "A tabular view of packet contents.",
|
||||
"template": autoflowTabularTemplate,
|
||||
"type": options && options.type,
|
||||
"needs": [
|
||||
"telemetry"
|
||||
],
|
||||
"delegation": true
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "AutoflowTabularController",
|
||||
"implementation": AutoflowTabularController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$timeout",
|
||||
"telemetrySubscriber"
|
||||
]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctAutoflowTable",
|
||||
"implementation": MCTAutoflowTable
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
openmct.legacyRegistry.enable("platform/features/autoflow");
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
26
platform/features/autoflow/res/templates/autoflow-tabular.html
Executable file
26
platform/features/autoflow/res/templates/autoflow-tabular.html
Executable file
@@ -0,0 +1,26 @@
|
||||
<div class="items-holder abs contents autoflow obj-value-format"
|
||||
ng-controller="AutoflowTabularController as autoflow">
|
||||
<div class="abs l-flex-row holder t-autoflow-header l-autoflow-header">
|
||||
<mct-include key="'input-filter'"
|
||||
ng-model="autoflow.filter"
|
||||
class="flex-elem">
|
||||
</mct-include>
|
||||
<div class="flex-elem grows t-last-update" title="Last Update">{{autoflow.updated()}}</div>
|
||||
<a title="Change column width"
|
||||
class="s-button flex-elem icon-arrows-right-left change-column-width"
|
||||
ng-click="autoflow.increaseColumnWidth()"></a>
|
||||
</div>
|
||||
<div class="abs t-autoflow-items l-autoflow-items"
|
||||
mct-resize="autoflow.setBounds(bounds)"
|
||||
mct-resize-interval="50">
|
||||
<mct-autoflow-table values="autoflow.rangeValues()"
|
||||
objects="autoflow.getTelemetryObjects()"
|
||||
rows="autoflow.getRows()"
|
||||
classes="autoflow.classes()"
|
||||
updated="autoflow.updated()"
|
||||
column-width="autoflow.columnWidth()"
|
||||
counter="autoflow.counter()"
|
||||
>
|
||||
</mct-autoflow-table>
|
||||
</div>
|
||||
</div>
|
||||
169
platform/features/autoflow/src/AutoflowTableLinker.js
Executable file
169
platform/features/autoflow/src/AutoflowTableLinker.js
Executable file
@@ -0,0 +1,169 @@
|
||||
/*global angular*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* The link step for the `mct-autoflow-table` directive;
|
||||
* watches scope and updates the DOM appropriately.
|
||||
* See documentation in `MCTAutoflowTable.js` for the rationale
|
||||
* for including this directive, as well as for an explanation
|
||||
* of which values are placed in scope.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Scope} scope the scope for this usage of the directive
|
||||
* @param element the jqLite-wrapped element which used this directive
|
||||
*/
|
||||
function AutoflowTableLinker(scope, element) {
|
||||
var objects, // Domain objects at last structure refresh
|
||||
rows, // Number of rows from last structure refresh
|
||||
priorClasses = {},
|
||||
valueSpans = {}; // Span elements to put data values in
|
||||
|
||||
// Create a new name-value pair in the specified column
|
||||
function createListItem(domainObject, ul) {
|
||||
// Create a new li, and spans to go in it.
|
||||
var li = angular.element('<li>'),
|
||||
titleSpan = angular.element('<span>'),
|
||||
valueSpan = angular.element('<span>');
|
||||
|
||||
// Place spans in the li, and li into the column.
|
||||
// valueSpan must precede titleSpan in the DOM due to new CSS float approach
|
||||
li.append(valueSpan).append(titleSpan);
|
||||
ul.append(li);
|
||||
|
||||
// Style appropriately
|
||||
li.addClass('l-autoflow-row');
|
||||
titleSpan.addClass('l-autoflow-item l');
|
||||
valueSpan.addClass('l-autoflow-item r l-obj-val-format');
|
||||
|
||||
// Set text/tooltip for the name-value row
|
||||
titleSpan.text(domainObject.getModel().name);
|
||||
titleSpan.attr("title", domainObject.getModel().name);
|
||||
|
||||
// Keep a reference to the span which will hold the
|
||||
// data value, to populate in the next refreshValues call
|
||||
valueSpans[domainObject.getId()] = valueSpan;
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
// Create a new column of name-value pairs in this table.
|
||||
function createColumn(el) {
|
||||
// Create a ul
|
||||
var ul = angular.element('<ul>');
|
||||
|
||||
// Add it into the mct-autoflow-table
|
||||
el.append(ul);
|
||||
|
||||
// Style appropriately
|
||||
ul.addClass('l-autoflow-col');
|
||||
|
||||
// Get the current col width and apply at time of column creation
|
||||
// Important to do this here, as new columns could be created after
|
||||
// the user has changed the width.
|
||||
ul.css('width', scope.columnWidth + 'px');
|
||||
|
||||
// Return it, so some li elements can be added
|
||||
return ul;
|
||||
}
|
||||
|
||||
// Change the width of the columns when user clicks the resize button.
|
||||
function resizeColumn() {
|
||||
element.find('ul').css('width', scope.columnWidth + 'px');
|
||||
}
|
||||
|
||||
// Rebuild the DOM associated with this table.
|
||||
function rebuild(domainObjects, rowCount) {
|
||||
var activeColumn;
|
||||
|
||||
// Empty out our cached span elements
|
||||
valueSpans = {};
|
||||
|
||||
// Start with an empty DOM beneath this directive
|
||||
element.html("");
|
||||
|
||||
// Add DOM elements for each domain object being displayed
|
||||
// in this table.
|
||||
domainObjects.forEach(function (object, index) {
|
||||
// Start a new column if we'd run out of room
|
||||
if (index % rowCount === 0) {
|
||||
activeColumn = createColumn(element);
|
||||
}
|
||||
// Add the DOM elements for that object to whichever
|
||||
// column (a `ul` element) is current.
|
||||
createListItem(object, activeColumn);
|
||||
});
|
||||
}
|
||||
|
||||
// Update spans with values, as made available via the
|
||||
// `values` attribute of this directive.
|
||||
function refreshValues() {
|
||||
// Get the available values
|
||||
var values = scope.values || {},
|
||||
classes = scope.classes || {};
|
||||
|
||||
// Populate all spans with those values (or clear
|
||||
// those spans if no value is available)
|
||||
(objects || []).forEach(function (object) {
|
||||
var id = object.getId(),
|
||||
span = valueSpans[id],
|
||||
value;
|
||||
|
||||
if (span) {
|
||||
// Look up the value...
|
||||
value = values[id];
|
||||
// ...and convert to empty string if it's undefined
|
||||
value = value === undefined ? "" : value;
|
||||
span.attr("data-value", value);
|
||||
|
||||
// Update the span
|
||||
span.text(value);
|
||||
span.attr("title", value);
|
||||
span.removeClass(priorClasses[id]);
|
||||
span.addClass(classes[id]);
|
||||
priorClasses[id] = classes[id];
|
||||
}
|
||||
// Also need stale/alert/ok class
|
||||
// on span
|
||||
});
|
||||
}
|
||||
|
||||
// Refresh the DOM for this table, if necessary
|
||||
function refreshStructure() {
|
||||
// Only rebuild if number of rows or set of objects
|
||||
// has changed; otherwise, our structure is still valid.
|
||||
if (scope.objects !== objects ||
|
||||
scope.rows !== rows) {
|
||||
|
||||
// Track those values to support future refresh checks
|
||||
objects = scope.objects;
|
||||
rows = scope.rows;
|
||||
|
||||
// Rebuild the DOM
|
||||
rebuild(objects || [], rows || 1);
|
||||
|
||||
// Refresh all data values shown
|
||||
refreshValues();
|
||||
}
|
||||
}
|
||||
|
||||
// Changing the domain objects in use or the number
|
||||
// of rows should trigger a structure change (DOM rebuild)
|
||||
scope.$watch("objects", refreshStructure);
|
||||
scope.$watch("rows", refreshStructure);
|
||||
|
||||
// When the current column width has been changed, resize the column
|
||||
scope.$watch('columnWidth', resizeColumn);
|
||||
|
||||
// When the last-updated time ticks,
|
||||
scope.$watch("updated", refreshValues);
|
||||
|
||||
// Update displayed values when the counter changes.
|
||||
scope.$watch("counter", refreshValues);
|
||||
|
||||
}
|
||||
|
||||
return AutoflowTableLinker;
|
||||
}
|
||||
);
|
||||
324
platform/features/autoflow/src/AutoflowTabularController.js
Executable file
324
platform/features/autoflow/src/AutoflowTabularController.js
Executable file
@@ -0,0 +1,324 @@
|
||||
|
||||
define(
|
||||
['moment'],
|
||||
function (moment) {
|
||||
|
||||
var ROW_HEIGHT = 16,
|
||||
SLIDER_HEIGHT = 10,
|
||||
INITIAL_COLUMN_WIDTH = 225,
|
||||
MAX_COLUMN_WIDTH = 525,
|
||||
COLUMN_WIDTH_STEP = 25,
|
||||
DEBOUNCE_INTERVAL = 100,
|
||||
DATE_FORMAT = "YYYY-DDD HH:mm:ss.SSS\\Z",
|
||||
NOT_UPDATED = "No updates",
|
||||
EMPTY_ARRAY = [];
|
||||
|
||||
/**
|
||||
* Responsible for supporting the autoflow tabular view.
|
||||
* Implements the all-over logic which drives that view,
|
||||
* mediating between template-provided areas, the included
|
||||
* `mct-autoflow-table` directive, and the underlying
|
||||
* domain object model.
|
||||
* @constructor
|
||||
*/
|
||||
function AutflowTabularController(
|
||||
$scope,
|
||||
$timeout,
|
||||
telemetrySubscriber
|
||||
) {
|
||||
var filterValue = "",
|
||||
filterValueLowercase = "",
|
||||
subscription,
|
||||
filteredObjects = [],
|
||||
lastUpdated = {},
|
||||
updateText = NOT_UPDATED,
|
||||
rangeValues = {},
|
||||
classes = {},
|
||||
limits = {},
|
||||
updatePending = false,
|
||||
lastBounce = Number.NEGATIVE_INFINITY,
|
||||
columnWidth = INITIAL_COLUMN_WIDTH,
|
||||
rows = 1,
|
||||
counter = 0;
|
||||
|
||||
// Trigger an update of the displayed table by incrementing
|
||||
// the counter that it watches.
|
||||
function triggerDisplayUpdate() {
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
// Check whether or not an object's name matches the
|
||||
// user-entered filter value.
|
||||
function filterObject(domainObject) {
|
||||
return (domainObject.getModel().name || "")
|
||||
.toLowerCase()
|
||||
.indexOf(filterValueLowercase) !== -1;
|
||||
}
|
||||
|
||||
// Comparator for sorting points back into packet order
|
||||
function compareObject(objectA, objectB) {
|
||||
var indexA = objectA.getModel().index || 0,
|
||||
indexB = objectB.getModel().index || 0;
|
||||
return indexA - indexB;
|
||||
}
|
||||
|
||||
// Update the list of currently-displayed objects; these
|
||||
// will be the subset of currently subscribed-to objects
|
||||
// which match a user-entered filter.
|
||||
function doUpdateFilteredObjects() {
|
||||
// Generate the list
|
||||
filteredObjects = (
|
||||
subscription ?
|
||||
subscription.getTelemetryObjects() :
|
||||
[]
|
||||
).filter(filterObject).sort(compareObject);
|
||||
|
||||
// Clear the pending flag
|
||||
updatePending = false;
|
||||
|
||||
// Track when this occurred, so that we can wait
|
||||
// a whole before updating again.
|
||||
lastBounce = Date.now();
|
||||
|
||||
triggerDisplayUpdate();
|
||||
}
|
||||
|
||||
// Request an update to the list of current objects; this may
|
||||
// run on a timeout to avoid excessive calls, e.g. while the user
|
||||
// is typing a filter.
|
||||
function updateFilteredObjects() {
|
||||
// Don't do anything if an update is already scheduled
|
||||
if (!updatePending) {
|
||||
if (Date.now() > lastBounce + DEBOUNCE_INTERVAL) {
|
||||
// Update immediately if it's been long enough
|
||||
doUpdateFilteredObjects();
|
||||
} else {
|
||||
// Otherwise, update later, and track that we have
|
||||
// an update pending so that subsequent calls can
|
||||
// be ignored.
|
||||
updatePending = true;
|
||||
$timeout(doUpdateFilteredObjects, DEBOUNCE_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Track the latest data values for this domain object
|
||||
function recordData(telemetryObject) {
|
||||
// Get latest domain/range values for this object.
|
||||
var id = telemetryObject.getId(),
|
||||
domainValue = subscription.getDomainValue(telemetryObject),
|
||||
rangeValue = subscription.getRangeValue(telemetryObject);
|
||||
|
||||
// Track the most recent timestamp change observed...
|
||||
if (domainValue !== undefined && domainValue !== lastUpdated[id]) {
|
||||
lastUpdated[id] = domainValue;
|
||||
// ... and update the displayable text for that timestamp
|
||||
updateText = isNaN(domainValue) ? "" :
|
||||
moment.utc(domainValue).format(DATE_FORMAT);
|
||||
}
|
||||
|
||||
// Store data values into the rangeValues structure, which
|
||||
// will be used to populate the table itself.
|
||||
// Note that we want full precision here.
|
||||
rangeValues[id] = rangeValue;
|
||||
|
||||
// Update limit states as well
|
||||
classes[id] = limits[id] && (limits[id].evaluate({
|
||||
// This relies on external knowledge that the
|
||||
// range value of a telemetry point is encoded
|
||||
// in its datum as "value."
|
||||
value: rangeValue
|
||||
}) || {}).cssClass;
|
||||
}
|
||||
|
||||
|
||||
// Look at telemetry objects from the subscription; this is watched
|
||||
// to detect changes from the subscription.
|
||||
function subscribedTelemetry() {
|
||||
return subscription ?
|
||||
subscription.getTelemetryObjects() : EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
// Update the data values which will be used to populate the table
|
||||
function updateValues() {
|
||||
subscribedTelemetry().forEach(recordData);
|
||||
triggerDisplayUpdate();
|
||||
}
|
||||
|
||||
// Getter-setter function for user-entered filter text.
|
||||
function filter(value) {
|
||||
// If value was specified, we're a setter
|
||||
if (value !== undefined) {
|
||||
// Store the new value
|
||||
filterValue = value;
|
||||
filterValueLowercase = value.toLowerCase();
|
||||
// Change which objects appear in the table
|
||||
updateFilteredObjects();
|
||||
}
|
||||
|
||||
// Always act as a getter
|
||||
return filterValue;
|
||||
}
|
||||
|
||||
// Update the bounds (width and height) of this view;
|
||||
// called from the mct-resize directive. Recalculates how
|
||||
// many rows should appear in the contained table.
|
||||
function setBounds(bounds) {
|
||||
var availableSpace = bounds.height - SLIDER_HEIGHT;
|
||||
rows = Math.max(1, Math.floor(availableSpace / ROW_HEIGHT));
|
||||
}
|
||||
|
||||
// Increment the current column width, up to the defined maximum.
|
||||
// When the max is hit, roll back to the default.
|
||||
function increaseColumnWidth() {
|
||||
columnWidth += COLUMN_WIDTH_STEP;
|
||||
// Cycle down to the initial width instead of exceeding max
|
||||
columnWidth = columnWidth > MAX_COLUMN_WIDTH ?
|
||||
INITIAL_COLUMN_WIDTH : columnWidth;
|
||||
}
|
||||
|
||||
// Get displayable text for last-updated value
|
||||
function updated() {
|
||||
return updateText;
|
||||
}
|
||||
|
||||
// Unsubscribe, if a subscription is active.
|
||||
function releaseSubscription() {
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscription = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Update set of telemetry objects managed by this view
|
||||
function updateTelemetryObjects(telemetryObjects) {
|
||||
updateFilteredObjects();
|
||||
limits = {};
|
||||
telemetryObjects.forEach(function (telemetryObject) {
|
||||
var id = telemetryObject.getId();
|
||||
limits[id] = telemetryObject.getCapability('limit');
|
||||
});
|
||||
}
|
||||
|
||||
// Create a subscription for the represented domain object.
|
||||
// This will resolve capability delegation as necessary.
|
||||
function makeSubscription(domainObject) {
|
||||
// Unsubscribe, if there is an existing subscription
|
||||
releaseSubscription();
|
||||
|
||||
// Clear updated timestamp
|
||||
lastUpdated = {};
|
||||
updateText = NOT_UPDATED;
|
||||
|
||||
// Create a new subscription; telemetrySubscriber gets
|
||||
// to do the meaningful work here.
|
||||
subscription = domainObject && telemetrySubscriber.subscribe(
|
||||
domainObject,
|
||||
updateValues
|
||||
);
|
||||
|
||||
// Our set of in-view telemetry objects may have changed,
|
||||
// so update the set that is being passed down to the table.
|
||||
updateFilteredObjects();
|
||||
}
|
||||
|
||||
// Watch for changes to the set of objects which have telemetry
|
||||
$scope.$watch(subscribedTelemetry, updateTelemetryObjects);
|
||||
|
||||
// Watch for the represented domainObject (this field will
|
||||
// be populated by mct-representation)
|
||||
$scope.$watch("domainObject", makeSubscription);
|
||||
|
||||
// Make sure we unsubscribe when this view is destroyed.
|
||||
$scope.$on("$destroy", releaseSubscription);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the number of rows which should be shown in this table.
|
||||
* @return {number} the number of rows to show
|
||||
*/
|
||||
getRows: function () {
|
||||
return rows;
|
||||
},
|
||||
/**
|
||||
* Get the objects which should currently be displayed in
|
||||
* this table. This will be watched, so the return value
|
||||
* should be stable when this list is unchanging. Only
|
||||
* objects which match the user-entered filter value should
|
||||
* be returned here.
|
||||
* @return {DomainObject[]} the domain objects to include in
|
||||
* this table.
|
||||
*/
|
||||
getTelemetryObjects: function () {
|
||||
return filteredObjects;
|
||||
},
|
||||
/**
|
||||
* Set the bounds (width/height) of this autoflow tabular view.
|
||||
* The template must ensure that these bounds are tracked on
|
||||
* the table area only.
|
||||
* @param bounds the bounds; and object with `width` and
|
||||
* `height` properties, both as numbers, in pixels.
|
||||
*/
|
||||
setBounds: setBounds,
|
||||
/**
|
||||
* Increments the width of the autoflow column.
|
||||
* Setting does not yet persist.
|
||||
*/
|
||||
increaseColumnWidth: increaseColumnWidth,
|
||||
/**
|
||||
* Get-or-set the user-supplied filter value.
|
||||
* @param {string} [value] the new filter value; omit to use
|
||||
* as a getter
|
||||
* @returns {string} the user-supplied filter value
|
||||
*/
|
||||
filter: filter,
|
||||
/**
|
||||
* Get all range values for use in this table. These will be
|
||||
* returned as an object of key-value pairs, where keys are
|
||||
* domain object IDs, and values are the most recently observed
|
||||
* data values associated with those objects, formatted for
|
||||
* display.
|
||||
* @returns {object.<string,string>} most recent values
|
||||
*/
|
||||
rangeValues: function () {
|
||||
return rangeValues;
|
||||
},
|
||||
/**
|
||||
* Get CSS classes to apply to specific rows, representing limit
|
||||
* states and/or stale states. These are returned as key-value
|
||||
* pairs where keys are domain object IDs, and values are CSS
|
||||
* classes to display for domain objects with those IDs.
|
||||
* @returns {object.<string,string>} CSS classes
|
||||
*/
|
||||
classes: function () {
|
||||
return classes;
|
||||
},
|
||||
/**
|
||||
* Get the "last updated" text for this view; this will be
|
||||
* the most recent timestamp observed for any telemetry-
|
||||
* providing object, formatted for display.
|
||||
* @returns {string} the time of the most recent update
|
||||
*/
|
||||
updated: updated,
|
||||
/**
|
||||
* Get the current column width, in pixels.
|
||||
* @returns {number} column width
|
||||
*/
|
||||
columnWidth: function () {
|
||||
return columnWidth;
|
||||
},
|
||||
/**
|
||||
* Keep a counter and increment this whenever the display
|
||||
* should be updated; this will be watched by the
|
||||
* `mct-autoflow-table`.
|
||||
* @returns {number} a counter value
|
||||
*/
|
||||
counter: function () {
|
||||
return counter;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return AutflowTabularController;
|
||||
}
|
||||
);
|
||||
60
platform/features/autoflow/src/MCTAutoflowTable.js
Executable file
60
platform/features/autoflow/src/MCTAutoflowTable.js
Executable file
@@ -0,0 +1,60 @@
|
||||
|
||||
define(
|
||||
["./AutoflowTableLinker"],
|
||||
function (AutoflowTableLinker) {
|
||||
|
||||
/**
|
||||
* The `mct-autoflow-table` directive specifically supports
|
||||
* autoflow tabular views; it is not intended for use outside
|
||||
* of that view.
|
||||
*
|
||||
* This directive is responsible for creating the structure
|
||||
* of the table in this view, and for updating its values.
|
||||
* While this is achievable using a regular Angular template,
|
||||
* this is undesirable from the perspective of performance
|
||||
* due to the number of watches that can be involved for large
|
||||
* tables. Instead, this directive will maintain a small number
|
||||
* of watches, rebuilding table structure only when necessary,
|
||||
* and updating displayed values in the more common case of
|
||||
* new data arriving.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function MCTAutoflowTable() {
|
||||
return {
|
||||
// Only applicable at the element level
|
||||
restrict: "E",
|
||||
|
||||
// The link function; handles DOM update/manipulation
|
||||
link: AutoflowTableLinker,
|
||||
|
||||
// Parameters to pass from attributes into scope
|
||||
scope: {
|
||||
// Set of domain objects to show in the table
|
||||
objects: "=",
|
||||
|
||||
// Values for those objects, by ID
|
||||
values: "=",
|
||||
|
||||
// CSS classes to show for objects, by ID
|
||||
classes: "=",
|
||||
|
||||
// Number of rows to show before autoflowing
|
||||
rows: "=",
|
||||
|
||||
// Time of last update; watched to refresh values
|
||||
updated: "=",
|
||||
|
||||
// Current width of the autoflow column
|
||||
columnWidth: "=",
|
||||
|
||||
// A counter used to trigger display updates
|
||||
counter: "="
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTAutoflowTable;
|
||||
|
||||
}
|
||||
);
|
||||
178
platform/features/autoflow/test/AutoflowTableLinkerSpec.js
Executable file
178
platform/features/autoflow/test/AutoflowTableLinkerSpec.js
Executable file
@@ -0,0 +1,178 @@
|
||||
|
||||
define(
|
||||
["../src/AutoflowTableLinker"],
|
||||
function (AutoflowTableLinker) {
|
||||
|
||||
describe("The mct-autoflow-table linker", function () {
|
||||
var cachedAngular,
|
||||
mockAngular,
|
||||
mockScope,
|
||||
mockElement,
|
||||
mockElements,
|
||||
linker;
|
||||
|
||||
// Utility function to generate more mock elements
|
||||
function createMockElement(html) {
|
||||
var mockEl = jasmine.createSpyObj(
|
||||
"element-" + html,
|
||||
[
|
||||
"append",
|
||||
"addClass",
|
||||
"removeClass",
|
||||
"text",
|
||||
"attr",
|
||||
"html",
|
||||
"css",
|
||||
"find"
|
||||
]
|
||||
);
|
||||
mockEl.testHtml = html;
|
||||
mockEl.append.andReturn(mockEl);
|
||||
mockElements.push(mockEl);
|
||||
return mockEl;
|
||||
}
|
||||
|
||||
function createMockDomainObject(id) {
|
||||
var mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject-" + id,
|
||||
["getId", "getModel"]
|
||||
);
|
||||
mockDomainObject.getId.andReturn(id);
|
||||
mockDomainObject.getModel.andReturn({name: id.toUpperCase()});
|
||||
return mockDomainObject;
|
||||
}
|
||||
|
||||
function fireWatch(watchExpression, value) {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === watchExpression) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// AutoflowTableLinker accesses Angular in the global
|
||||
// scope, since it is not injectable; we simulate that
|
||||
// here by adding/removing it to/from the window object.
|
||||
beforeEach(function () {
|
||||
mockElements = [];
|
||||
|
||||
mockAngular = jasmine.createSpyObj("angular", ["element"]);
|
||||
mockScope = jasmine.createSpyObj("scope", ["$watch"]);
|
||||
mockElement = createMockElement('<div>');
|
||||
|
||||
mockAngular.element.andCallFake(createMockElement);
|
||||
|
||||
if (window.angular !== undefined) {
|
||||
cachedAngular = window.angular;
|
||||
}
|
||||
window.angular = mockAngular;
|
||||
|
||||
linker = new AutoflowTableLinker(mockScope, mockElement);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
if (cachedAngular !== undefined) {
|
||||
window.angular = cachedAngular;
|
||||
} else {
|
||||
delete window.angular;
|
||||
}
|
||||
});
|
||||
|
||||
it("watches for changes in inputs", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"objects",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"rows",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"counter",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("changes structure when domain objects change", function () {
|
||||
// Set up scope
|
||||
mockScope.rows = 4;
|
||||
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
.map(createMockDomainObject);
|
||||
|
||||
// Fire an update to the set of objects
|
||||
fireWatch("objects");
|
||||
|
||||
// Should have rebuilt with two columns of
|
||||
// four and two rows each; first, by clearing...
|
||||
expect(mockElement.html).toHaveBeenCalledWith("");
|
||||
|
||||
// Should have appended two columns...
|
||||
expect(mockElement.append.calls.length).toEqual(2);
|
||||
|
||||
// ...which should have received two and four rows each
|
||||
expect(mockElement.append.calls[0].args[0].append.calls.length)
|
||||
.toEqual(4);
|
||||
expect(mockElement.append.calls[1].args[0].append.calls.length)
|
||||
.toEqual(2);
|
||||
});
|
||||
|
||||
it("updates values", function () {
|
||||
var mockSpans;
|
||||
|
||||
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
.map(createMockDomainObject);
|
||||
mockScope.values = { a: 0 };
|
||||
|
||||
// Fire an update to the set of values
|
||||
fireWatch("objects");
|
||||
fireWatch("updated");
|
||||
|
||||
// Get all created spans
|
||||
mockSpans = mockElements.filter(function (mockElem) {
|
||||
return mockElem.testHtml === '<span>';
|
||||
});
|
||||
|
||||
// First span should be a, should have gotten this value.
|
||||
// This test detects, in particular, WTD-749
|
||||
expect(mockSpans[0].text).toHaveBeenCalledWith('A');
|
||||
expect(mockSpans[1].text).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it("listens for changes in column width", function () {
|
||||
var mockUL = createMockElement("<ul>");
|
||||
mockElement.find.andReturn(mockUL);
|
||||
mockScope.columnWidth = 200;
|
||||
fireWatch("columnWidth", mockScope.columnWidth);
|
||||
expect(mockUL.css).toHaveBeenCalledWith("width", "200px");
|
||||
});
|
||||
|
||||
it("updates CSS classes", function () {
|
||||
var mockSpans;
|
||||
|
||||
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
.map(createMockDomainObject);
|
||||
mockScope.values = { a: "a value to find" };
|
||||
mockScope.classes = { a: 'class-a' };
|
||||
|
||||
// Fire an update to the set of values
|
||||
fireWatch("objects");
|
||||
fireWatch("updated");
|
||||
|
||||
// Figure out which span holds the relevant value...
|
||||
mockSpans = mockElements.filter(function (mockElem) {
|
||||
return mockElem.testHtml === '<span>';
|
||||
}).filter(function (mockSpan) {
|
||||
var attrCalls = mockSpan.attr.calls;
|
||||
return attrCalls.some(function (call) {
|
||||
return call.args[0] === 'title' &&
|
||||
call.args[1] === mockScope.values.a;
|
||||
});
|
||||
});
|
||||
|
||||
// ...and make sure it also has had its class applied
|
||||
expect(mockSpans[0].addClass)
|
||||
.toHaveBeenCalledWith(mockScope.classes.a);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
341
platform/features/autoflow/test/AutoflowTabularControllerSpec.js
Executable file
341
platform/features/autoflow/test/AutoflowTabularControllerSpec.js
Executable file
@@ -0,0 +1,341 @@
|
||||
|
||||
define(
|
||||
["../src/AutoflowTabularController"],
|
||||
function (AutoflowTabularController) {
|
||||
|
||||
describe("The autoflow tabular controller", function () {
|
||||
var mockScope,
|
||||
mockTimeout,
|
||||
mockSubscriber,
|
||||
mockDomainObject,
|
||||
mockSubscription,
|
||||
controller;
|
||||
|
||||
// Fire watches that are registered as functions.
|
||||
function fireFnWatches() {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (typeof call.args[0] === 'function') {
|
||||
call.args[1](call.args[0]());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$on", "$watch"]
|
||||
);
|
||||
mockTimeout = jasmine.createSpy("$timeout");
|
||||
mockSubscriber = jasmine.createSpyObj(
|
||||
"telemetrySubscriber",
|
||||
["subscribe"]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getModel", "getCapability"]
|
||||
);
|
||||
mockSubscription = jasmine.createSpyObj(
|
||||
"subscription",
|
||||
[
|
||||
"unsubscribe",
|
||||
"getTelemetryObjects",
|
||||
"getDomainValue",
|
||||
"getRangeValue"
|
||||
]
|
||||
);
|
||||
|
||||
mockSubscriber.subscribe.andReturn(mockSubscription);
|
||||
mockDomainObject.getModel.andReturn({name: "something"});
|
||||
|
||||
controller = new AutoflowTabularController(
|
||||
mockScope,
|
||||
mockTimeout,
|
||||
mockSubscriber
|
||||
);
|
||||
});
|
||||
|
||||
it("listens for the represented domain object", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"domainObject",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("provides a getter-setter function for filtering", function () {
|
||||
expect(controller.filter()).toEqual("");
|
||||
controller.filter("something");
|
||||
expect(controller.filter()).toEqual("something");
|
||||
});
|
||||
|
||||
it("tracks bounds and adjust number of rows accordingly", function () {
|
||||
// Rows are 15px high, and need room for an 10px slider
|
||||
controller.setBounds({ width: 700, height: 120 });
|
||||
expect(controller.getRows()).toEqual(6); // 110 usable height / 16px
|
||||
controller.setBounds({ width: 700, height: 240 });
|
||||
expect(controller.getRows()).toEqual(14); // 230 usable height / 16px
|
||||
});
|
||||
|
||||
it("subscribes to a represented object's telemetry", function () {
|
||||
// Set up subscription, scope
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
// Invoke the watcher with represented domain object
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Should have subscribed to it
|
||||
expect(mockSubscriber.subscribe).toHaveBeenCalledWith(
|
||||
mockDomainObject,
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
// Should report objects as reported from subscription
|
||||
expect(controller.getTelemetryObjects())
|
||||
.toEqual([mockDomainObject]);
|
||||
});
|
||||
|
||||
it("releases subscriptions on destroy", function () {
|
||||
// Set up subscription...
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Verify precondition
|
||||
expect(mockSubscription.unsubscribe).not.toHaveBeenCalled();
|
||||
|
||||
// Make sure we're listening for $destroy
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
"$destroy",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
// Fire a destroy event
|
||||
mockScope.$on.mostRecentCall.args[1]();
|
||||
|
||||
// Should have unsubscribed
|
||||
expect(mockSubscription.unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("presents latest values and latest update state", function () {
|
||||
// Make sure values are available
|
||||
mockSubscription.getDomainValue.andReturn(402654321123);
|
||||
mockSubscription.getRangeValue.andReturn(789);
|
||||
mockDomainObject.getId.andReturn('testId');
|
||||
|
||||
// Set up subscription...
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Fire subscription callback
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
|
||||
// ...and exposed the results for template to consume
|
||||
expect(controller.updated()).toEqual("1982-278 08:25:21.123Z");
|
||||
expect(controller.rangeValues().testId).toEqual(789);
|
||||
});
|
||||
|
||||
it("sorts domain objects by index", function () {
|
||||
var testIndexes = { a: 2, b: 1, c: 3, d: 0 },
|
||||
mockDomainObjects = Object.keys(testIndexes).sort().map(function (id) {
|
||||
var mockDomainObj = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getModel"]
|
||||
);
|
||||
|
||||
mockDomainObj.getId.andReturn(id);
|
||||
mockDomainObj.getModel.andReturn({ index: testIndexes[id] });
|
||||
|
||||
return mockDomainObj;
|
||||
});
|
||||
|
||||
// Expose those domain objects...
|
||||
mockSubscription.getTelemetryObjects.andReturn(mockDomainObjects);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Fire subscription callback
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
|
||||
// Controller should expose same objects, but sorted by index from model
|
||||
expect(controller.getTelemetryObjects()).toEqual([
|
||||
mockDomainObjects[3], // d, index=0
|
||||
mockDomainObjects[1], // b, index=1
|
||||
mockDomainObjects[0], // a, index=2
|
||||
mockDomainObjects[2] // c, index=3
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses a timeout to throttle update", function () {
|
||||
// Set up subscription...
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
// Set the object in view; should not need a timeout
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
expect(mockTimeout.calls.length).toEqual(0);
|
||||
|
||||
// Next call should schedule an update on a timeout
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
expect(mockTimeout.calls.length).toEqual(1);
|
||||
|
||||
// ...but this last one should not, since existing
|
||||
// timeout will cover it
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
expect(mockTimeout.calls.length).toEqual(1);
|
||||
});
|
||||
|
||||
it("allows changing column width", function () {
|
||||
var initialWidth = controller.columnWidth();
|
||||
controller.increaseColumnWidth();
|
||||
expect(controller.columnWidth()).toBeGreaterThan(initialWidth);
|
||||
});
|
||||
|
||||
describe("filter", function () {
|
||||
var doFilter,
|
||||
filteredObjects,
|
||||
filteredObjectNames;
|
||||
|
||||
beforeEach(function () {
|
||||
var telemetryObjects,
|
||||
updateFilteredObjects;
|
||||
|
||||
telemetryObjects = [
|
||||
'DEF123',
|
||||
'abc789',
|
||||
'456abc',
|
||||
'4ab3cdef',
|
||||
'hjs[12].*(){}^\\'
|
||||
].map(function (objectName, index) {
|
||||
var mockTelemetryObject = jasmine.createSpyObj(
|
||||
objectName,
|
||||
["getId", "getModel"]
|
||||
);
|
||||
|
||||
mockTelemetryObject.getId.andReturn(objectName);
|
||||
mockTelemetryObject.getModel.andReturn({
|
||||
name: objectName,
|
||||
index: index
|
||||
});
|
||||
|
||||
return mockTelemetryObject;
|
||||
});
|
||||
|
||||
mockSubscription
|
||||
.getTelemetryObjects
|
||||
.andReturn(telemetryObjects);
|
||||
|
||||
// Trigger domainObject change to create subscription.
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
updateFilteredObjects = function () {
|
||||
filteredObjects = controller.getTelemetryObjects();
|
||||
filteredObjectNames = filteredObjects.map(function (o) {
|
||||
return o.getModel().name;
|
||||
});
|
||||
};
|
||||
|
||||
doFilter = function (term) {
|
||||
controller.filter(term);
|
||||
// Filter is debounced so we have to force it to occur.
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
updateFilteredObjects();
|
||||
};
|
||||
|
||||
updateFilteredObjects();
|
||||
});
|
||||
|
||||
it("initially shows all objects", function () {
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'DEF123',
|
||||
'abc789',
|
||||
'456abc',
|
||||
'4ab3cdef',
|
||||
'hjs[12].*(){}^\\'
|
||||
]);
|
||||
});
|
||||
|
||||
it("by blank string matches all objects", function () {
|
||||
doFilter('');
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'DEF123',
|
||||
'abc789',
|
||||
'456abc',
|
||||
'4ab3cdef',
|
||||
'hjs[12].*(){}^\\'
|
||||
]);
|
||||
});
|
||||
|
||||
it("exactly matches an object name", function () {
|
||||
doFilter('4ab3cdef');
|
||||
expect(filteredObjectNames).toEqual(['4ab3cdef']);
|
||||
});
|
||||
|
||||
it("partially matches object names", function () {
|
||||
doFilter('abc');
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'abc789',
|
||||
'456abc'
|
||||
]);
|
||||
});
|
||||
|
||||
it("matches case insensitive names", function () {
|
||||
doFilter('def');
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'DEF123',
|
||||
'4ab3cdef'
|
||||
]);
|
||||
});
|
||||
|
||||
it("works as expected with special characters", function () {
|
||||
doFilter('[12]');
|
||||
expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']);
|
||||
doFilter('.*');
|
||||
expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']);
|
||||
doFilter('.*()');
|
||||
expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']);
|
||||
doFilter('.*?');
|
||||
expect(filteredObjectNames).toEqual([]);
|
||||
doFilter('.+');
|
||||
expect(filteredObjectNames).toEqual([]);
|
||||
});
|
||||
|
||||
it("exposes CSS classes from limits", function () {
|
||||
var id = mockDomainObject.getId(),
|
||||
testClass = "some-css-class",
|
||||
mockLimitCapability =
|
||||
jasmine.createSpyObj('limit', ['evaluate']);
|
||||
|
||||
mockDomainObject.getCapability.andCallFake(function (key) {
|
||||
return key === 'limit' && mockLimitCapability;
|
||||
});
|
||||
mockLimitCapability.evaluate
|
||||
.andReturn({ cssClass: testClass });
|
||||
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
|
||||
fireFnWatches();
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
|
||||
expect(controller.classes()[id]).toEqual(testClass);
|
||||
});
|
||||
|
||||
it("exposes a counter that changes with each update", function () {
|
||||
var i, prior;
|
||||
|
||||
for (i = 0; i < 10; i += 1) {
|
||||
prior = controller.counter();
|
||||
expect(controller.counter()).toEqual(prior);
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
expect(controller.counter()).not.toEqual(prior);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
39
platform/features/autoflow/test/MCTAutoflowTableSpec.js
Executable file
39
platform/features/autoflow/test/MCTAutoflowTableSpec.js
Executable file
@@ -0,0 +1,39 @@
|
||||
|
||||
define(
|
||||
["../src/MCTAutoflowTable"],
|
||||
function (MCTAutoflowTable) {
|
||||
|
||||
describe("The mct-autoflow-table directive", function () {
|
||||
var mctAutoflowTable;
|
||||
|
||||
beforeEach(function () {
|
||||
mctAutoflowTable = new MCTAutoflowTable();
|
||||
});
|
||||
|
||||
// Real functionality is contained/tested in the linker,
|
||||
// so just check to make sure we're exposing the directive
|
||||
// appropriately.
|
||||
it("is applicable at the element level", function () {
|
||||
expect(mctAutoflowTable.restrict).toEqual("E");
|
||||
});
|
||||
|
||||
it("two-ways binds needed scope variables", function () {
|
||||
expect(mctAutoflowTable.scope).toEqual({
|
||||
objects: "=",
|
||||
values: "=",
|
||||
rows: "=",
|
||||
updated: "=",
|
||||
classes: "=",
|
||||
columnWidth: "=",
|
||||
counter: "="
|
||||
});
|
||||
});
|
||||
|
||||
it("provides a link function", function () {
|
||||
expect(mctAutoflowTable.link).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -36,9 +36,7 @@ define(
|
||||
* @param {ActionContext} context the context for this action
|
||||
*/
|
||||
function FollowTimerAction(timerService, context) {
|
||||
var domainObject =
|
||||
context.domainObject &&
|
||||
context.domainObject.useCapability('adapter');
|
||||
var domainObject = context.domainObject;
|
||||
this.perform =
|
||||
timerService.setTimer.bind(timerService, domainObject);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ define(
|
||||
|
||||
FollowIndicator.prototype.getText = function () {
|
||||
var timer = this.timerService.getTimer();
|
||||
return timer ? ('Following timer ' + timer.name) : NO_TIMER;
|
||||
return (timer) ? 'Following timer ' + timer.getModel().name : NO_TIMER;
|
||||
};
|
||||
|
||||
FollowIndicator.prototype.getDescription = function () {
|
||||
|
||||
@@ -32,7 +32,6 @@ define(['EventEmitter'], function (EventEmitter) {
|
||||
function TimerService(openmct) {
|
||||
EventEmitter.apply(this);
|
||||
this.time = openmct.time;
|
||||
this.objects = openmct.objects;
|
||||
}
|
||||
|
||||
TimerService.prototype = Object.create(EventEmitter.prototype);
|
||||
@@ -45,16 +44,6 @@ define(['EventEmitter'], function (EventEmitter) {
|
||||
TimerService.prototype.setTimer = function (timer) {
|
||||
this.timer = timer;
|
||||
this.emit('change');
|
||||
|
||||
if (this.stopObserving) {
|
||||
this.stopObserving();
|
||||
delete this.stopObserving;
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
this.stopObserving =
|
||||
this.objects.observe(timer, '*', this.setTimer.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -84,16 +73,16 @@ define(['EventEmitter'], function (EventEmitter) {
|
||||
var clock = this.time.clock();
|
||||
var canConvert = this.hasTimer() &&
|
||||
!!clock &&
|
||||
this.timer.timerState !== 'stopped';
|
||||
this.timer.getModel().timerState !== 'stopped';
|
||||
|
||||
if (!canConvert) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var now = clock.currentValue();
|
||||
var delta = this.timer.timerState === 'paused' ?
|
||||
now - this.timer.pausedTime : 0;
|
||||
var epoch = this.timer.timestamp;
|
||||
var model = this.timer.getModel();
|
||||
var delta = model.timerState === 'paused' ? now - model.pausedTime : 0;
|
||||
var epoch = model.timestamp;
|
||||
|
||||
return timestamp - epoch - delta;
|
||||
};
|
||||
|
||||
@@ -29,19 +29,12 @@ define([
|
||||
describe("The Follow Timer action", function () {
|
||||
var testContext;
|
||||
var testModel;
|
||||
var testAdaptedObject;
|
||||
|
||||
beforeEach(function () {
|
||||
testModel = {};
|
||||
testContext = { domainObject: jasmine.createSpyObj('domainObject', [
|
||||
'getModel',
|
||||
'useCapability'
|
||||
]) };
|
||||
testAdaptedObject = { foo: 'bar' };
|
||||
testContext.domainObject.getModel.andReturn(testModel);
|
||||
testContext.domainObject.useCapability.andCallFake(function (c) {
|
||||
return c === 'adapter' && testAdaptedObject;
|
||||
});
|
||||
testContext = { domainObject: { getModel: function () {
|
||||
return testModel;
|
||||
} } };
|
||||
});
|
||||
|
||||
it("is applicable to timers", function () {
|
||||
@@ -79,7 +72,7 @@ define([
|
||||
|
||||
it("sets the active timer", function () {
|
||||
expect(mockTimerService.setTimer)
|
||||
.toHaveBeenCalledWith(testAdaptedObject);
|
||||
.toHaveBeenCalledWith(testContext.domainObject);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,15 +42,18 @@ define(["../../src/indicators/FollowIndicator"], function (FollowIndicator) {
|
||||
});
|
||||
|
||||
describe("when a timer is set", function () {
|
||||
var testObject;
|
||||
var testModel;
|
||||
var mockDomainObject;
|
||||
|
||||
beforeEach(function () {
|
||||
testObject = { name: "some timer!" };
|
||||
mockTimerService.getTimer.andReturn(testObject);
|
||||
testModel = { name: "some timer!" };
|
||||
mockDomainObject = jasmine.createSpyObj('timer', ['getModel']);
|
||||
mockDomainObject.getModel.andReturn(testModel);
|
||||
mockTimerService.getTimer.andReturn(mockDomainObject);
|
||||
});
|
||||
|
||||
it("displays the timer's name", function () {
|
||||
expect(indicator.getText().indexOf(testObject.name))
|
||||
expect(indicator.getText().indexOf(testModel.name))
|
||||
.not.toEqual(-1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,10 +30,7 @@ define([
|
||||
|
||||
beforeEach(function () {
|
||||
callback = jasmine.createSpy('callback');
|
||||
mockmct = {
|
||||
time: { clock: jasmine.createSpy('clock') },
|
||||
objects: { observe: jasmine.createSpy('observe') }
|
||||
};
|
||||
mockmct = { time: { clock: jasmine.createSpy('clock') } };
|
||||
timerService = new TimerService(mockmct);
|
||||
timerService.on('change', callback);
|
||||
});
|
||||
@@ -61,17 +58,6 @@ define([
|
||||
it("reports the current timer", function () {
|
||||
expect(timerService.getTimer()).toBe(testTimer);
|
||||
});
|
||||
|
||||
it("observes changes to an object", function () {
|
||||
var newTimer = { name: "I am another timer." };
|
||||
expect(mockmct.objects.observe).toHaveBeenCalledWith(
|
||||
testTimer,
|
||||
'*',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
mockmct.objects.observe.mostRecentCall.args[2](newTimer);
|
||||
expect(timerService.getTimer()).toBe(newTimer);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -255,8 +255,6 @@ define(
|
||||
if (this.nextDatum) {
|
||||
this.updateValues(this.nextDatum);
|
||||
delete this.nextDatum;
|
||||
} else {
|
||||
this.updateValues(this.$scope.imageHistory[this.$scope.imageHistory.length - 1]);
|
||||
}
|
||||
this.autoScroll = true;
|
||||
}
|
||||
|
||||
@@ -183,17 +183,6 @@ define(
|
||||
expect(controller.getImageUrl()).toEqual(newUrl);
|
||||
});
|
||||
|
||||
it("forwards large image view to latest image in history on un-pause", function () {
|
||||
$scope.imageHistory = [
|
||||
{ utc: 1434600258122, url: 'some/url1', selected: false},
|
||||
{ utc: 1434600258123, url: 'some/url2', selected: false}
|
||||
];
|
||||
controller.paused(true);
|
||||
controller.paused(false);
|
||||
|
||||
expect(controller.getImageUrl()).toEqual(controller.getImageUrl($scope.imageHistory[1]));
|
||||
});
|
||||
|
||||
it("subscribes to telemetry", function () {
|
||||
expect(openmct.telemetry.subscribe).toHaveBeenCalledWith(
|
||||
newDomainObject,
|
||||
@@ -238,7 +227,7 @@ define(
|
||||
expect(controller.updateHistory(mockDatum)).toBe(false);
|
||||
});
|
||||
|
||||
describe("when user clicks on imagery thumbnail", function () {
|
||||
describe("user clicks on imagery thumbnail", function () {
|
||||
var mockDatum = { utc: 1434600258123, url: 'some/url', selected: false};
|
||||
|
||||
it("pauses and adds selected class to imagery thumbnail", function () {
|
||||
@@ -259,7 +248,6 @@ define(
|
||||
expect(controller.getTime()).toEqual(controller.timeFormat.format(mockDatum.utc));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("initially shows an empty string for date/time", function () {
|
||||
|
||||
@@ -260,9 +260,7 @@ define([
|
||||
"key": "LayoutController",
|
||||
"implementation": LayoutController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$element",
|
||||
"openmct"
|
||||
"$scope"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -272,8 +270,7 @@ define([
|
||||
"$scope",
|
||||
"$q",
|
||||
"dialogService",
|
||||
"openmct",
|
||||
"$element"
|
||||
"openmct"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
ng-controller="FixedController as controller">
|
||||
|
||||
<!-- Background grid -->
|
||||
<div class="l-grid-holder" ng-click="controller.bypassSelection($event)">
|
||||
<div class="l-grid-holder" ng-click="controller.clearSelection()">
|
||||
<div class="l-grid l-grid-x"
|
||||
ng-if="!controller.getGridSize()[0] < 3"
|
||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
||||
@@ -35,28 +35,33 @@
|
||||
<!-- Fixed position elements -->
|
||||
<div ng-repeat="element in controller.getElements()"
|
||||
class="l-fixed-position-item s-selectable s-moveable s-hover-border"
|
||||
ng-class="{
|
||||
's-not-selected': controller.selected() && !controller.selected(element),
|
||||
's-selected': controller.selected(element)
|
||||
}"
|
||||
ng-style="element.style"
|
||||
mct-selectable="controller.getContext(element)"
|
||||
mct-init-select="controller.shouldSelect(element)">
|
||||
ng-click="controller.select(element)">
|
||||
<mct-include key="element.template"
|
||||
parameters="{ gridSize: controller.getGridSize() }"
|
||||
ng-model="element">
|
||||
</mct-include>
|
||||
</mct-include>
|
||||
</div>
|
||||
|
||||
<!-- Selection highlight, handles -->
|
||||
<span class="s-selected s-moveable" ng-if="controller.isElementSelected()">
|
||||
<span class="s-selected s-moveable" ng-if="controller.selected()">
|
||||
<div class="l-fixed-position-item t-edit-handle-holder"
|
||||
mct-drag-down="controller.moveHandle().startDrag()"
|
||||
mct-drag-down="controller.moveHandle().startDrag(controller.selected())"
|
||||
mct-drag="controller.moveHandle().continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag()"
|
||||
ng-style="controller.getSelectedElementStyle()">
|
||||
mct-drag-up="controller.moveHandle().endDrag()"
|
||||
ng-style="controller.selected().style">
|
||||
</div>
|
||||
<div ng-repeat="handle in controller.handles()"
|
||||
class="l-fixed-position-item-handle edit-corner"
|
||||
ng-style="handle.style()"
|
||||
mct-drag-down="handle.startDrag()"
|
||||
mct-drag="handle.continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag(handle)">
|
||||
mct-drag-up="handle.endDrag()">
|
||||
</div>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -22,12 +22,10 @@
|
||||
|
||||
<div class="abs l-layout"
|
||||
ng-controller="LayoutController as controller"
|
||||
ng-click="controller.bypassSelection($event)">
|
||||
ng-click="controller.clearSelection()">
|
||||
|
||||
<!-- Background grid -->
|
||||
<div class="l-grid-holder"
|
||||
ng-show="!controller.drilledIn"
|
||||
ng-click="controller.bypassSelection($event)">
|
||||
<div class="l-grid-holder" ng-click="controller.clearSelection()">
|
||||
<div class="l-grid l-grid-x"
|
||||
ng-if="!controller.getGridSize()[0] < 3"
|
||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
||||
@@ -36,13 +34,10 @@
|
||||
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
||||
</div>
|
||||
|
||||
<div class="abs frame t-frame-outer child-frame panel s-selectable s-moveable s-hover-border t-object-type-{{ childObject.getModel().type }}"
|
||||
data-layout-id="{{childObject.getId() + '-' + $id}}"
|
||||
ng-class="{ 'no-frame': !controller.hasFrame(childObject), 's-drilled-in': controller.isDrilledIn(childObject) }"
|
||||
<div class='abs frame t-frame-outer child-frame panel s-selectable s-moveable s-hover-border'
|
||||
ng-class="{ 'no-frame': !controller.hasFrame(childObject), 's-selected':controller.selected(childObject) }"
|
||||
ng-repeat="childObject in composition"
|
||||
ng-init="controller.selectIfNew(childObject.getId() + '-' + $id, childObject)"
|
||||
mct-selectable="controller.getContext(childObject, true)"
|
||||
ng-dblclick="controller.drill($event, childObject)"
|
||||
ng-click="controller.select($event, childObject.getId())"
|
||||
ng-style="controller.getFrameStyle(childObject.getId())">
|
||||
|
||||
<mct-representation key="'frame'"
|
||||
@@ -50,7 +45,7 @@
|
||||
mct-object="childObject">
|
||||
</mct-representation>
|
||||
<!-- Drag handles -->
|
||||
<span class="abs t-edit-handle-holder" ng-if="controller.selected(childObject) && !controller.isDrilledIn(childObject)">
|
||||
<span class="abs t-edit-handle-holder s-hover-border" ng-if="controller.selected(childObject)">
|
||||
<span class="edit-handle edit-move"
|
||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [0,0])"
|
||||
mct-drag="controller.continueDrag(delta)"
|
||||
@@ -78,6 +73,7 @@
|
||||
mct-drag-up="controller.endDrag()">
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -47,7 +47,7 @@ define(
|
||||
* @constructor
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function FixedController($scope, $q, dialogService, openmct, $element) {
|
||||
function FixedController($scope, $q, dialogService, openmct) {
|
||||
this.names = {}; // Cache names by ID
|
||||
this.values = {}; // Cache values by ID
|
||||
this.elementProxiesById = {};
|
||||
@@ -55,11 +55,9 @@ define(
|
||||
this.telemetryObjects = [];
|
||||
this.subscriptions = [];
|
||||
this.openmct = openmct;
|
||||
this.$element = $element;
|
||||
this.$scope = $scope;
|
||||
|
||||
this.gridSize = $scope.domainObject && $scope.domainObject.getModel().layoutGrid;
|
||||
this.fixedViewSelectable = false;
|
||||
|
||||
var self = this;
|
||||
[
|
||||
@@ -89,8 +87,9 @@ define(
|
||||
|
||||
// Update the style for a selected element
|
||||
function updateSelectionStyle() {
|
||||
if (self.selectedElementProxy) {
|
||||
self.selectedElementProxy.style = convertPosition(self.selectedElementProxy);
|
||||
var element = self.selection && self.selection.get();
|
||||
if (element) {
|
||||
element.style = convertPosition(element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,19 +136,25 @@ define(
|
||||
|
||||
// Decorate elements in the current configuration
|
||||
function refreshElements() {
|
||||
var elements = (($scope.configuration || {}).elements || []);
|
||||
// Cache selection; we are instantiating new proxies
|
||||
// so we may want to restore this.
|
||||
var selected = self.selection && self.selection.get(),
|
||||
elements = (($scope.configuration || {}).elements || []),
|
||||
index = -1; // Start with a 'not-found' value
|
||||
|
||||
// Find the selection in the new array
|
||||
if (selected !== undefined) {
|
||||
index = elements.indexOf(selected.element);
|
||||
}
|
||||
|
||||
// Create the new proxies...
|
||||
self.elementProxies = elements.map(makeProxyElement);
|
||||
|
||||
// If selection is not in array, select parent.
|
||||
// Otherwise, set the element to select after refresh.
|
||||
if (self.selectedElementProxy) {
|
||||
var index = elements.indexOf(self.selectedElementProxy.element);
|
||||
if (index === -1) {
|
||||
self.$element[0].click();
|
||||
} else if (!self.elementToSelectAfterRefresh) {
|
||||
self.elementToSelectAfterRefresh = self.elementProxies[index].element;
|
||||
// Clear old selection, and restore if appropriate
|
||||
if (self.selection) {
|
||||
self.selection.deselect();
|
||||
if (index > -1) {
|
||||
self.select(self.elementProxies[index]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,12 +224,12 @@ define(
|
||||
$scope.configuration.elements || [];
|
||||
// Store the position of this element.
|
||||
$scope.configuration.elements.push(element);
|
||||
|
||||
self.elementToSelectAfterRefresh = element;
|
||||
|
||||
// Refresh displayed elements
|
||||
refreshElements();
|
||||
|
||||
// Select the newly-added element
|
||||
self.select(
|
||||
self.elementProxies[self.elementProxies.length - 1]
|
||||
);
|
||||
// Mark change as persistable
|
||||
if ($scope.commit) {
|
||||
$scope.commit("Dropped an element.");
|
||||
@@ -258,36 +263,21 @@ define(
|
||||
self.getTelemetry($scope.domainObject);
|
||||
}
|
||||
|
||||
// Sets the selectable object in response to the selection change event.
|
||||
function setSelection(selectable) {
|
||||
var selection = selectable[0];
|
||||
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection.context.elementProxy) {
|
||||
self.selectedElementProxy = selection.context.elementProxy;
|
||||
self.mvHandle = self.generateDragHandle(self.selectedElementProxy);
|
||||
self.resizeHandles = self.generateDragHandles(self.selectedElementProxy);
|
||||
} else {
|
||||
// Make fixed view selectable if it's not already.
|
||||
if (!self.fixedViewSelectable) {
|
||||
self.fixedViewSelectable = true;
|
||||
selection.context.viewProxy = new FixedProxy(addElement, $q, dialogService);
|
||||
self.openmct.selection.select(selection);
|
||||
}
|
||||
|
||||
self.resizeHandles = [];
|
||||
self.mvHandle = undefined;
|
||||
self.selectedElementProxy = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this.elementProxies = [];
|
||||
this.generateDragHandle = generateDragHandle;
|
||||
this.generateDragHandles = generateDragHandles;
|
||||
this.updateSelectionStyle = updateSelectionStyle;
|
||||
|
||||
// Track current selection state
|
||||
$scope.$watch("selection", function (selection) {
|
||||
this.selection = selection;
|
||||
|
||||
// Expose the view's selection proxy
|
||||
if (this.selection) {
|
||||
this.selection.proxy(
|
||||
new FixedProxy(addElement, $q, dialogService)
|
||||
);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
// Detect changes to grid size
|
||||
$scope.$watch("model.layoutGrid", updateElementPositions);
|
||||
@@ -308,13 +298,10 @@ define(
|
||||
$scope.$on("$destroy", function () {
|
||||
self.unsubscribe();
|
||||
self.openmct.time.off("bounds", updateDisplayBounds);
|
||||
self.openmct.selection.off("change", setSelection);
|
||||
});
|
||||
|
||||
// Respond to external bounds changes
|
||||
this.openmct.time.on("bounds", updateDisplayBounds);
|
||||
this.openmct.selection.on('change', setSelection);
|
||||
this.$element.on('click', this.bypassSelection.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,47 +360,22 @@ define(
|
||||
*/
|
||||
FixedController.prototype.updateView = function (telemetryObject, datum) {
|
||||
var metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
var telemetryKeyToDisplay = this.chooseTelemetryKeyToDisplay(metadata);
|
||||
var formattedTelemetryValue = this.getFormattedTelemetryValueForKey(telemetryKeyToDisplay, datum, metadata);
|
||||
var rangeMetadata = metadata.valuesForHints(['range'])[0];
|
||||
var rangeKey = rangeMetadata.source || rangeMetadata.key;
|
||||
var valueMetadata = metadata.value(rangeKey);
|
||||
var limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
|
||||
var alarm = limitEvaluator && limitEvaluator.evaluate(datum, telemetryKeyToDisplay);
|
||||
var formatter = this.openmct.telemetry.getValueFormatter(valueMetadata);
|
||||
var value = datum[valueMetadata.key];
|
||||
var alarm = limitEvaluator && limitEvaluator.evaluate(datum, rangeKey);
|
||||
|
||||
this.setDisplayedValue(
|
||||
telemetryObject,
|
||||
formattedTelemetryValue,
|
||||
formatter.format(value),
|
||||
alarm && alarm.cssClass
|
||||
);
|
||||
this.digest();
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
FixedController.prototype.getFormattedTelemetryValueForKey = function (telemetryKeyToDisplay, datum, metadata) {
|
||||
var valueMetadata = metadata.value(telemetryKeyToDisplay);
|
||||
var formatter = this.openmct.telemetry.getValueFormatter(valueMetadata);
|
||||
|
||||
return formatter.format(datum[valueMetadata.key]);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
FixedController.prototype.chooseTelemetryKeyToDisplay = function (metadata) {
|
||||
// If there is a range value, show that preferentially
|
||||
var telemetryKeyToDisplay = metadata.valuesForHints(['range'])[0];
|
||||
|
||||
// If no range is defined, default to the highest priority non time-domain data.
|
||||
if (telemetryKeyToDisplay === undefined) {
|
||||
var valuesOrderedByPriority = metadata.values();
|
||||
telemetryKeyToDisplay = valuesOrderedByPriority.filter(function (valueMetadata) {
|
||||
return !(valueMetadata.hints.domain);
|
||||
})[0];
|
||||
}
|
||||
|
||||
return telemetryKeyToDisplay.source;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request the last historical data point for the given domain objects
|
||||
* @param {object[]} objects
|
||||
@@ -426,9 +388,7 @@ define(
|
||||
objects.forEach(function (object) {
|
||||
self.openmct.telemetry.request(object, {start: bounds.start, end: bounds.end, size: 1})
|
||||
.then(function (data) {
|
||||
if (data.length > 0) {
|
||||
self.updateView(object, data[data.length - 1]);
|
||||
}
|
||||
self.updateView(object, data[data.length - 1]);
|
||||
});
|
||||
});
|
||||
return objects;
|
||||
@@ -505,56 +465,38 @@ define(
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the element should be selected or not.
|
||||
*
|
||||
* @param elementProxy the element to check
|
||||
* @returns {boolean} true if the element should be selected.
|
||||
* Check if the element is currently selected, or (if no
|
||||
* argument is supplied) get the currently selected element.
|
||||
* @returns {boolean} true if selected
|
||||
*/
|
||||
FixedController.prototype.shouldSelect = function (elementProxy) {
|
||||
if (elementProxy.element === this.elementToSelectAfterRefresh) {
|
||||
delete this.elementToSelectAfterRefresh;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
FixedController.prototype.selected = function (element) {
|
||||
var selection = this.selection;
|
||||
return selection && ((arguments.length > 0) ?
|
||||
selection.selected(element) : selection.get());
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the active user selection in this view.
|
||||
* @param element the element to select
|
||||
*/
|
||||
FixedController.prototype.select = function select(element) {
|
||||
if (this.selection) {
|
||||
// Update selection...
|
||||
this.selection.select(element);
|
||||
// ...as well as move, resize handles
|
||||
this.mvHandle = this.generateDragHandle(element);
|
||||
this.resizeHandles = this.generateDragHandles(element);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if an element is currently selected.
|
||||
*
|
||||
* @returns {boolean} true if an element is selected.
|
||||
* Clear the current user selection.
|
||||
*/
|
||||
FixedController.prototype.isElementSelected = function () {
|
||||
return (this.selectedElementProxy) ? true : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the style for the selected element.
|
||||
*
|
||||
* @returns {string} element style
|
||||
*/
|
||||
FixedController.prototype.getSelectedElementStyle = function () {
|
||||
return (this.selectedElementProxy) ? this.selectedElementProxy.style : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the selected element.
|
||||
*
|
||||
* @returns the selected element
|
||||
*/
|
||||
FixedController.prototype.getSelectedElement = function () {
|
||||
return this.selectedElementProxy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevents the event from bubbling up if drag is in progress.
|
||||
*/
|
||||
FixedController.prototype.bypassSelection = function ($event) {
|
||||
if (this.dragInProgress) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
return;
|
||||
FixedController.prototype.clearSelection = function () {
|
||||
if (this.selection) {
|
||||
this.selection.deselect();
|
||||
this.resizeHandles = [];
|
||||
this.mvHandle = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -575,38 +517,6 @@ define(
|
||||
return this.mvHandle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the selection context.
|
||||
*
|
||||
* @param elementProxy the element proxy
|
||||
* @returns {object} the context object which includes elementProxy and toolbar
|
||||
*/
|
||||
FixedController.prototype.getContext = function (elementProxy) {
|
||||
return {
|
||||
elementProxy: elementProxy,
|
||||
toolbar: elementProxy
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* End drag.
|
||||
*
|
||||
* @param handle the resize handle
|
||||
*/
|
||||
FixedController.prototype.endDrag = function (handle) {
|
||||
this.dragInProgress = true;
|
||||
|
||||
setTimeout(function () {
|
||||
this.dragInProgress = false;
|
||||
}.bind(this), 0);
|
||||
|
||||
if (handle) {
|
||||
handle.endDrag();
|
||||
} else {
|
||||
this.moveHandle().endDrag();
|
||||
}
|
||||
};
|
||||
|
||||
return FixedController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ define(
|
||||
* Start a drag gesture. This should be called when a drag
|
||||
* begins to track initial state.
|
||||
*/
|
||||
FixedDragHandle.prototype.startDrag = function () {
|
||||
FixedDragHandle.prototype.startDrag = function startDrag() {
|
||||
// Cache initial x/y positions
|
||||
this.dragging = {
|
||||
x: this.elementHandle.x(),
|
||||
|
||||
@@ -26,14 +26,8 @@
|
||||
* @namespace platform/features/layout
|
||||
*/
|
||||
define(
|
||||
[
|
||||
'zepto',
|
||||
'./LayoutDrag'
|
||||
],
|
||||
function (
|
||||
$,
|
||||
LayoutDrag
|
||||
) {
|
||||
['./LayoutDrag'],
|
||||
function (LayoutDrag) {
|
||||
|
||||
var DEFAULT_DIMENSIONS = [12, 8],
|
||||
DEFAULT_GRID_SIZE = [32, 32],
|
||||
@@ -52,12 +46,10 @@ define(
|
||||
* @constructor
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function LayoutController($scope, $element, openmct) {
|
||||
function LayoutController($scope) {
|
||||
var self = this,
|
||||
callbackCount = 0;
|
||||
|
||||
this.$element = $element;
|
||||
|
||||
// Update grid size when it changed
|
||||
function updateGridSize(layoutGrid) {
|
||||
var oldSize = self.gridSize;
|
||||
@@ -127,11 +119,10 @@ define(
|
||||
self.layoutPanels(ids);
|
||||
self.setFrames(ids);
|
||||
|
||||
if (self.selectedId &&
|
||||
self.selectedId !== $scope.domainObject.getId() &&
|
||||
composition.indexOf(self.selectedId) === -1) {
|
||||
// Click triggers selection of layout parent.
|
||||
self.$element[0].click();
|
||||
// If there is a newly-dropped object, select it.
|
||||
if (self.droppedIdToSelectAfterRefresh) {
|
||||
self.select(null, self.droppedIdToSelectAfterRefresh);
|
||||
delete self.droppedIdToSelectAfterRefresh;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -163,39 +154,22 @@ define(
|
||||
}
|
||||
};
|
||||
|
||||
// Sets the selectable object in response to the selection change event.
|
||||
function setSelection(selectable) {
|
||||
var selection = selectable[0];
|
||||
|
||||
if (!selection) {
|
||||
delete self.selectedId;
|
||||
return;
|
||||
}
|
||||
|
||||
self.selectedId = selection.context.oldItem.getId();
|
||||
self.drilledIn = undefined;
|
||||
self.selectable = selectable;
|
||||
}
|
||||
|
||||
this.positions = {};
|
||||
this.rawPositions = {};
|
||||
this.gridSize = DEFAULT_GRID_SIZE;
|
||||
this.$scope = $scope;
|
||||
this.drilledIn = undefined;
|
||||
this.openmct = openmct;
|
||||
|
||||
// Watch for changes to the grid size in the model
|
||||
$scope.$watch("model.layoutGrid", updateGridSize);
|
||||
|
||||
$scope.$watch("selection", function (selection) {
|
||||
this.selection = selection;
|
||||
}.bind(this));
|
||||
|
||||
// Update composed objects on screen, and position panes
|
||||
$scope.$watchCollection("model.composition", refreshComposition);
|
||||
|
||||
openmct.selection.on('change', setSelection);
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
openmct.selection.off("change", setSelection);
|
||||
});
|
||||
|
||||
// Position panes where they are dropped
|
||||
$scope.$on("mctDrop", handleDrop);
|
||||
}
|
||||
|
||||
@@ -377,14 +351,37 @@ define(
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the object is currently selected.
|
||||
* Check if the object is currently selected.
|
||||
*
|
||||
* @param {string} obj the object to check for selection
|
||||
* @returns {boolean} true if selected, otherwise false
|
||||
*/
|
||||
LayoutController.prototype.selected = function (obj) {
|
||||
var sobj = this.openmct.selection.get()[0];
|
||||
return (sobj && sobj.context.oldItem.getId() === obj.getId()) ? true : false;
|
||||
return !!this.selectedId && this.selectedId === obj.getId();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the active user selection in this view.
|
||||
*
|
||||
* @param event the mouse event
|
||||
* @param {string} id the object id
|
||||
*/
|
||||
LayoutController.prototype.select = function (event, id) {
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
if (this.selection) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
this.selectedId = id;
|
||||
|
||||
var selectedObj = {};
|
||||
selectedObj[this.frames[id] ? 'hideFrame' : 'showFrame'] = this.toggleFrame.bind(this, id);
|
||||
|
||||
if (this.selection) {
|
||||
this.selection.select(selectedObj);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -393,7 +390,7 @@ define(
|
||||
* @param {string} id the object id
|
||||
* @private
|
||||
*/
|
||||
LayoutController.prototype.toggleFrame = function (id, domainObject) {
|
||||
LayoutController.prototype.toggleFrame = function (id) {
|
||||
var configuration = this.$scope.configuration;
|
||||
|
||||
if (!configuration.panels[id]) {
|
||||
@@ -401,75 +398,21 @@ define(
|
||||
}
|
||||
|
||||
this.frames[id] = configuration.panels[id].hasFrame = !this.frames[id];
|
||||
|
||||
var selection = this.openmct.selection.get();
|
||||
selection[0].context.toolbar = this.getToolbar(id, domainObject);
|
||||
this.openmct.selection.select(selection); // reselect so toolbar updates
|
||||
this.select(undefined, id); // reselect so toolbar updates
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the toolbar object for the given domain object.
|
||||
*
|
||||
* @param id the domain object id
|
||||
* @param domainObject the domain object
|
||||
* @returns {object}
|
||||
* @private
|
||||
* Clear the current user selection.
|
||||
*/
|
||||
LayoutController.prototype.getToolbar = function (id, domainObject) {
|
||||
var toolbarObj = {};
|
||||
toolbarObj[this.frames[id] ? 'hideFrame' : 'showFrame'] = this.toggleFrame.bind(this, id, domainObject);
|
||||
return toolbarObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Bypasses selection if drag is in progress.
|
||||
*
|
||||
* @param event the angular event object
|
||||
*/
|
||||
LayoutController.prototype.bypassSelection = function (event) {
|
||||
LayoutController.prototype.clearSelection = function () {
|
||||
if (this.dragInProgress) {
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the domain object is drilled in.
|
||||
*
|
||||
* @param domainObject the domain object
|
||||
* @return true if the object is drilled in, false otherwise
|
||||
*/
|
||||
LayoutController.prototype.isDrilledIn = function (domainObject) {
|
||||
return this.drilledIn === domainObject.getId();
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts the given object in the drilled-in mode.
|
||||
*
|
||||
* @param event the angular event object
|
||||
* @param domainObject the domain object
|
||||
*/
|
||||
LayoutController.prototype.drill = function (event, domainObject) {
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (!domainObject.getCapability('editor').inEditContext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!domainObject.hasCapability('composition')) {
|
||||
return;
|
||||
if (this.selection) {
|
||||
this.selection.deselect();
|
||||
delete this.selectedId;
|
||||
}
|
||||
|
||||
// Disable since fixed position doesn't use the selection API yet
|
||||
if (domainObject.getModel().type === 'telemetry.fixed') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.drilledIn = domainObject.getId();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -491,36 +434,6 @@ define(
|
||||
return this.gridSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the selection context.
|
||||
*
|
||||
* @param domainObject the domain object
|
||||
* @returns {object} the context object which includes
|
||||
* item, oldItem and toolbar
|
||||
*/
|
||||
LayoutController.prototype.getContext = function (domainObject, toolbar) {
|
||||
return {
|
||||
item: domainObject.useCapability('adapter'),
|
||||
oldItem: domainObject,
|
||||
toolbar: toolbar ? this.getToolbar(domainObject.getId(), domainObject) : undefined
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects a newly-dropped object.
|
||||
*
|
||||
* @param classSelector the css class selector
|
||||
* @param domainObject the domain object
|
||||
*/
|
||||
LayoutController.prototype.selectIfNew = function (selector, domainObject) {
|
||||
if (domainObject.getId() === this.droppedIdToSelectAfterRefresh) {
|
||||
setTimeout(function () {
|
||||
$('[data-layout-id="' + selector + '"]')[0].click();
|
||||
delete this.droppedIdToSelectAfterRefresh;
|
||||
}.bind(this), 0);
|
||||
}
|
||||
};
|
||||
|
||||
return LayoutController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -77,7 +77,6 @@ define([
|
||||
overlayContainer;
|
||||
|
||||
function openOverlay() {
|
||||
|
||||
// Remove frame classes from being applied in a non-frame context
|
||||
$(frame).removeClass('frame frame-template');
|
||||
overlay = document.createElement('div');
|
||||
|
||||
@@ -55,8 +55,8 @@ define(
|
||||
* @param element the fixed position element, as stored in its
|
||||
* configuration
|
||||
* @param index the element's index within its array
|
||||
* @param {Array} elements the full array of elements
|
||||
* @param {number[]} gridSize the current layout grid size in [x,y] from
|
||||
* @param {Array} elements the full array of elements
|
||||
*/
|
||||
function ElementProxy(element, index, elements, gridSize) {
|
||||
/**
|
||||
|
||||
@@ -21,14 +21,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"../src/FixedController",
|
||||
"zepto"
|
||||
],
|
||||
function (
|
||||
FixedController,
|
||||
$
|
||||
) {
|
||||
["../src/FixedController"],
|
||||
function (FixedController) {
|
||||
|
||||
describe("The Fixed Position controller", function () {
|
||||
var mockScope,
|
||||
@@ -52,9 +46,6 @@ define(
|
||||
mockMetadata,
|
||||
mockTimeSystem,
|
||||
mockLimitEvaluator,
|
||||
mockSelection,
|
||||
$element = [],
|
||||
selectable = [],
|
||||
controller;
|
||||
|
||||
// Utility function; find a watch for a given expression
|
||||
@@ -187,36 +178,23 @@ define(
|
||||
Promise.resolve(mockChildren)
|
||||
);
|
||||
|
||||
|
||||
mockScope.model = testModel;
|
||||
mockScope.configuration = testConfiguration;
|
||||
|
||||
selectable[0] = {
|
||||
context: {
|
||||
oldItem: mockDomainObject
|
||||
}
|
||||
};
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'select',
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andCallThrough();
|
||||
mockScope.selection = jasmine.createSpyObj(
|
||||
'selection',
|
||||
['select', 'get', 'selected', 'deselect', 'proxy']
|
||||
);
|
||||
|
||||
mockOpenMCT = {
|
||||
time: mockConductor,
|
||||
telemetry: mockTelemetryAPI,
|
||||
composition: mockCompositionAPI,
|
||||
selection: mockSelection
|
||||
composition: mockCompositionAPI
|
||||
};
|
||||
|
||||
$element = $('<div></div>');
|
||||
spyOn($element[0], 'click');
|
||||
|
||||
mockMetadata = jasmine.createSpyObj('mockMetadata', [
|
||||
'valuesForHints',
|
||||
'value',
|
||||
'values'
|
||||
'value'
|
||||
]);
|
||||
mockMetadata.value.andReturn({
|
||||
key: 'value'
|
||||
@@ -248,11 +226,11 @@ define(
|
||||
mockScope,
|
||||
mockQ,
|
||||
mockDialogService,
|
||||
mockOpenMCT,
|
||||
$element
|
||||
mockOpenMCT
|
||||
);
|
||||
|
||||
findWatch("model.layoutGrid")(testModel.layoutGrid);
|
||||
findWatch("selection")(mockScope.selection);
|
||||
});
|
||||
|
||||
it("subscribes when a domain object is available", function () {
|
||||
@@ -328,41 +306,41 @@ define(
|
||||
});
|
||||
|
||||
it("allows elements to be selected", function () {
|
||||
testModel.modified = 1;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
selectable[0].context.elementProxy = controller.getElements()[1];
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
|
||||
expect(controller.isElementSelected()).toBe(true);
|
||||
});
|
||||
|
||||
it("allows selection retrieval", function () {
|
||||
var elements;
|
||||
|
||||
testModel.modified = 1;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
elements = controller.getElements();
|
||||
selectable[0].context.elementProxy = elements[1];
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
|
||||
expect(controller.getSelectedElement()).toEqual(elements[1]);
|
||||
controller.select(elements[1]);
|
||||
expect(mockScope.selection.select)
|
||||
.toHaveBeenCalledWith(elements[1]);
|
||||
});
|
||||
|
||||
it("selects the parent view when selected element is removed", function () {
|
||||
it("allows selection retrieval", function () {
|
||||
// selected with no arguments should give the current
|
||||
// selection
|
||||
var elements;
|
||||
|
||||
testModel.modified = 1;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
var elements = controller.getElements();
|
||||
selectable[0].context.elementProxy = elements[1];
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
elements = controller.getElements();
|
||||
controller.select(elements[1]);
|
||||
mockScope.selection.get.andReturn(elements[1]);
|
||||
expect(controller.selected()).toEqual(elements[1]);
|
||||
});
|
||||
|
||||
elements[1].remove();
|
||||
testModel.modified = 2;
|
||||
it("allows selections to be cleared", function () {
|
||||
var elements;
|
||||
|
||||
testModel.modified = 1;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
expect($element[0].click).toHaveBeenCalled();
|
||||
elements = controller.getElements();
|
||||
controller.select(elements[1]);
|
||||
controller.clearSelection();
|
||||
expect(controller.selected(elements[1])).toBeFalsy();
|
||||
});
|
||||
|
||||
it("retains selections during refresh", function () {
|
||||
@@ -374,21 +352,23 @@ define(
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
elements = controller.getElements();
|
||||
selectable[0].context.elementProxy = elements[1];
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
controller.select(elements[1]);
|
||||
|
||||
expect(controller.getSelectedElement()).toEqual(elements[1]);
|
||||
// Verify precondition
|
||||
expect(mockScope.selection.select.calls.length).toEqual(1);
|
||||
|
||||
// Mimic selection behavior
|
||||
mockScope.selection.get.andReturn(elements[1]);
|
||||
|
||||
elements[2].remove();
|
||||
testModel.modified = 2;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
elements = controller.getElements();
|
||||
|
||||
// Verify removal, as test assumes this
|
||||
expect(elements.length).toEqual(2);
|
||||
|
||||
expect(controller.shouldSelect(elements[1])).toBe(true);
|
||||
expect(mockScope.selection.select.calls.length).toEqual(2);
|
||||
});
|
||||
|
||||
it("Displays received values for telemetry elements", function () {
|
||||
@@ -525,25 +505,21 @@ define(
|
||||
});
|
||||
|
||||
it("exposes a view-level selection proxy", function () {
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
var selection = mockOpenMCT.selection.select.mostRecentCall.args[0];
|
||||
|
||||
expect(mockOpenMCT.selection.select).toHaveBeenCalled();
|
||||
expect(selection.context.viewProxy).toBeDefined();
|
||||
expect(mockScope.selection.proxy).toHaveBeenCalledWith(
|
||||
jasmine.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
it("exposes drag handles", function () {
|
||||
var handles;
|
||||
|
||||
// Select something so that drag handles are expected
|
||||
testModel.modified = 1;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
selectable[0].context.elementProxy = controller.getElements()[1];
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
controller.select(controller.getElements()[1]);
|
||||
|
||||
// Should have a non-empty array of handles
|
||||
handles = controller.handles();
|
||||
|
||||
expect(handles).toEqual(jasmine.any(Array));
|
||||
expect(handles.length).not.toEqual(0);
|
||||
|
||||
@@ -556,14 +532,15 @@ define(
|
||||
});
|
||||
|
||||
it("exposes a move handle", function () {
|
||||
var handle;
|
||||
|
||||
// Select something so that drag handles are expected
|
||||
testModel.modified = 1;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
selectable[0].context.elementProxy = controller.getElements()[1];
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
controller.select(controller.getElements()[1]);
|
||||
|
||||
// Should have a move handle
|
||||
var handle = controller.moveHandle();
|
||||
handle = controller.moveHandle();
|
||||
|
||||
// And it should have start/continue/end drag methods
|
||||
expect(handle.startDrag).toEqual(jasmine.any(Function));
|
||||
@@ -574,40 +551,26 @@ define(
|
||||
it("updates selection style during drag", function () {
|
||||
var oldStyle;
|
||||
|
||||
// Select something so that drag handles are expected
|
||||
testModel.modified = 1;
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
|
||||
selectable[0].context.elementProxy = controller.getElements()[1];
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
controller.select(controller.getElements()[1]);
|
||||
mockScope.selection.get.andReturn(controller.getElements()[1]);
|
||||
|
||||
// Get style
|
||||
oldStyle = controller.getSelectedElementStyle();
|
||||
oldStyle = controller.selected().style;
|
||||
|
||||
// Start a drag gesture
|
||||
controller.moveHandle().startDrag();
|
||||
|
||||
// Haven't moved yet; style shouldn't have updated yet
|
||||
expect(controller.getSelectedElementStyle()).toEqual(oldStyle);
|
||||
expect(controller.selected().style).toEqual(oldStyle);
|
||||
|
||||
// Drag a little
|
||||
controller.moveHandle().continueDrag([1000, 100]);
|
||||
|
||||
// Style should have been updated
|
||||
expect(controller.getSelectedElementStyle()).not.toEqual(oldStyle);
|
||||
});
|
||||
|
||||
it("cleans up slection on scope destroy", function () {
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
'$destroy',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
mockScope.$on.mostRecentCall.args[1]();
|
||||
|
||||
expect(mockOpenMCT.selection.off).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
expect(controller.selected().style).not.toEqual(oldStyle);
|
||||
});
|
||||
|
||||
describe("on display bounds changes", function () {
|
||||
@@ -690,39 +653,6 @@ define(
|
||||
});
|
||||
});
|
||||
|
||||
it("selects an range value to display, if available", function () {
|
||||
mockMetadata.valuesForHints.andReturn([
|
||||
{
|
||||
key: 'range',
|
||||
source: 'range'
|
||||
}
|
||||
]);
|
||||
var key = controller.chooseTelemetryKeyToDisplay(mockMetadata);
|
||||
expect(key).toEqual('range');
|
||||
});
|
||||
|
||||
it("selects the first non-domain value to display, if no range available", function () {
|
||||
mockMetadata.valuesForHints.andReturn([]);
|
||||
mockMetadata.values.andReturn([
|
||||
{
|
||||
key: 'domain',
|
||||
source: 'domain',
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'image',
|
||||
source: 'image',
|
||||
hints: {
|
||||
image: 1
|
||||
}
|
||||
}
|
||||
]);
|
||||
var key = controller.chooseTelemetryKeyToDisplay(mockMetadata);
|
||||
expect(key).toEqual('image');
|
||||
});
|
||||
|
||||
it("reflects limit status", function () {
|
||||
mockLimitEvaluator.evaluate.andReturn({cssClass: "alarm-a"});
|
||||
controller.updateView(mockTelemetryObject, [{
|
||||
@@ -739,14 +669,6 @@ define(
|
||||
expect(controller.getElements()[0].cssClass).toEqual("alarm-a");
|
||||
});
|
||||
});
|
||||
|
||||
it("listens for selection change events", function () {
|
||||
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,14 +21,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"../src/LayoutController",
|
||||
"zepto"
|
||||
],
|
||||
function (
|
||||
LayoutController,
|
||||
$
|
||||
) {
|
||||
["../src/LayoutController"],
|
||||
function (LayoutController) {
|
||||
|
||||
describe("The Layout controller", function () {
|
||||
var mockScope,
|
||||
@@ -38,12 +32,7 @@ define(
|
||||
controller,
|
||||
mockCompositionCapability,
|
||||
mockComposition,
|
||||
mockCompositionObjects,
|
||||
mockOpenMCT,
|
||||
mockSelection,
|
||||
mockDomainObjectCapability,
|
||||
$element = [],
|
||||
selectable = [];
|
||||
mockCompositionObjects;
|
||||
|
||||
function mockPromise(value) {
|
||||
return {
|
||||
@@ -69,18 +58,21 @@ define(
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
getCapability: function () {
|
||||
return mockDomainObjectCapability;
|
||||
},
|
||||
hasCapability: function (param) {
|
||||
if (param === 'composition') {
|
||||
return id !== 'b';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Utility function to find a watch for a given expression
|
||||
function findWatch(expr) {
|
||||
var watch;
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
watch = call.args[1];
|
||||
}
|
||||
});
|
||||
return watch;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
@@ -96,6 +88,7 @@ define(
|
||||
mockComposition = ["a", "b", "c"];
|
||||
mockCompositionObjects = mockComposition.map(mockDomainObject);
|
||||
|
||||
|
||||
testConfiguration = {
|
||||
panels: {
|
||||
a: {
|
||||
@@ -104,70 +97,27 @@ define(
|
||||
}
|
||||
}
|
||||
};
|
||||
mockDomainObjectCapability = jasmine.createSpyObj('capability',
|
||||
['inEditContext']
|
||||
);
|
||||
|
||||
mockCompositionCapability = mockPromise(mockCompositionObjects);
|
||||
|
||||
mockScope.domainObject = mockDomainObject("mockDomainObject");
|
||||
mockScope.model = testModel;
|
||||
mockScope.configuration = testConfiguration;
|
||||
|
||||
selectable[0] = {
|
||||
context: {
|
||||
oldItem: mockScope.domainObject
|
||||
}
|
||||
};
|
||||
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'select',
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn(selectable);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection
|
||||
};
|
||||
|
||||
$element = $('<div></div>');
|
||||
$(document).find('body').append($element);
|
||||
spyOn($element[0], 'click');
|
||||
mockScope.selection = jasmine.createSpyObj(
|
||||
'selection',
|
||||
['select', 'get', 'selected', 'deselect']
|
||||
);
|
||||
|
||||
spyOn(mockScope.domainObject, "useCapability").andCallThrough();
|
||||
|
||||
controller = new LayoutController(mockScope, $element, mockOpenMCT);
|
||||
controller = new LayoutController(mockScope);
|
||||
spyOn(controller, "layoutPanels").andCallThrough();
|
||||
|
||||
findWatch("selection")(mockScope.selection);
|
||||
|
||||
jasmine.Clock.useMock();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
$element.remove();
|
||||
});
|
||||
|
||||
|
||||
it("listens for selection change events", function () {
|
||||
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("cleans up on scope destroy", function () {
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
'$destroy',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
mockScope.$on.calls[0].args[1]();
|
||||
|
||||
expect(mockOpenMCT.selection.off).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
// Model changes will indicate that panel positions
|
||||
// may have changed, for instance.
|
||||
it("watches for changes to composition", function () {
|
||||
@@ -370,35 +320,67 @@ define(
|
||||
.not.toEqual(oldStyle);
|
||||
});
|
||||
|
||||
it("allows objects to be selected", function () {
|
||||
it("allows panels to be selected", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[0];
|
||||
selectable[0].context.oldItem = childObj;
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
|
||||
controller.select(mockEvent, childObj.getId());
|
||||
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
||||
|
||||
expect(controller.selected(childObj)).toBe(true);
|
||||
});
|
||||
|
||||
it("prevents event bubbling while drag is in progress", function () {
|
||||
it("allows selection to be cleared", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[0];
|
||||
|
||||
controller.select(null, childObj.getId());
|
||||
controller.clearSelection();
|
||||
|
||||
expect(controller.selected(childObj)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("prevents clearing selection while drag is in progress", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[0];
|
||||
var id = childObj.getId();
|
||||
|
||||
controller.select(mockEvent, id);
|
||||
|
||||
// Do a drag
|
||||
controller.startDrag(childObj.getId(), [1, 1], [0, 0]);
|
||||
controller.startDrag(id, [1, 1], [0, 0]);
|
||||
controller.continueDrag([100, 100]);
|
||||
controller.endDrag();
|
||||
|
||||
// Because mouse position could cause the parent object to be selected, this should be ignored.
|
||||
controller.bypassSelection(mockEvent);
|
||||
// Because mouse position could cause clearSelection to be called, this should be ignored.
|
||||
controller.clearSelection();
|
||||
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
||||
expect(controller.selected(childObj)).toBe(true);
|
||||
|
||||
// Shoud be able to select another object when dragging is done.
|
||||
// Shoud be able to clear the selection after dragging is done.
|
||||
jasmine.Clock.tick(0);
|
||||
mockEvent.stopPropagation.reset();
|
||||
controller.bypassSelection(mockEvent);
|
||||
controller.clearSelection();
|
||||
|
||||
expect(mockEvent.stopPropagation).not.toHaveBeenCalled();
|
||||
expect(controller.selected(childObj)).toBe(false);
|
||||
});
|
||||
|
||||
it("clears selection after moving/resizing", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[0];
|
||||
var id = childObj.getId();
|
||||
|
||||
controller.select(mockEvent, id);
|
||||
|
||||
// Do a drag
|
||||
controller.startDrag(id, [1, 1], [0, 0]);
|
||||
controller.continueDrag([100, 100]);
|
||||
controller.endDrag();
|
||||
|
||||
jasmine.Clock.tick(0);
|
||||
controller.clearSelection();
|
||||
|
||||
expect(controller.selected(childObj)).toBe(false);
|
||||
});
|
||||
|
||||
it("shows frames by default", function () {
|
||||
@@ -416,74 +398,32 @@ define(
|
||||
it("hides frame when selected object has frame ", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[0];
|
||||
selectable[0].context.oldItem = childObj;
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
var toolbarObj = controller.getToolbar(childObj.getId(), childObj);
|
||||
controller.select(mockEvent, childObj.getId());
|
||||
|
||||
expect(mockScope.selection.select).toHaveBeenCalled();
|
||||
|
||||
var selectedObj = mockScope.selection.select.mostRecentCall.args[0];
|
||||
|
||||
expect(controller.hasFrame(childObj)).toBe(true);
|
||||
expect(toolbarObj.hideFrame).toBeDefined();
|
||||
expect(toolbarObj.hideFrame).toEqual(jasmine.any(Function));
|
||||
expect(selectedObj.hideFrame).toBeDefined();
|
||||
expect(selectedObj.hideFrame).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("shows frame when selected object has no frame", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
var childObj = mockCompositionObjects[1];
|
||||
selectable[0].context.oldItem = childObj;
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
var toolbarObj = controller.getToolbar(childObj.getId(), childObj);
|
||||
controller.select(mockEvent, childObj.getId());
|
||||
|
||||
expect(mockScope.selection.select).toHaveBeenCalled();
|
||||
|
||||
var selectedObj = mockScope.selection.select.mostRecentCall.args[0];
|
||||
|
||||
expect(controller.hasFrame(childObj)).toBe(false);
|
||||
expect(toolbarObj.showFrame).toBeDefined();
|
||||
expect(toolbarObj.showFrame).toEqual(jasmine.any(Function));
|
||||
expect(selectedObj.showFrame).toBeDefined();
|
||||
expect(selectedObj.showFrame).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("selects the parent object when selected object is removed", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[0];
|
||||
selectable[0].context.oldItem = childObj;
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
|
||||
var composition = ["b", "c"];
|
||||
mockScope.$watchCollection.mostRecentCall.args[1](composition);
|
||||
|
||||
expect($element[0].click).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("allows objects to be drilled-in only when editing", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[0];
|
||||
childObj.getCapability().inEditContext.andReturn(false);
|
||||
controller.drill(mockEvent, childObj);
|
||||
|
||||
expect(controller.isDrilledIn(childObj)).toBe(false);
|
||||
});
|
||||
|
||||
it("allows objects to be drilled-in only if it has sub objects", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
var childObj = mockCompositionObjects[1];
|
||||
childObj.getCapability().inEditContext.andReturn(true);
|
||||
controller.drill(mockEvent, childObj);
|
||||
|
||||
expect(controller.isDrilledIn(childObj)).toBe(false);
|
||||
});
|
||||
|
||||
it("selects a newly-dropped object", function () {
|
||||
mockScope.$on.mostRecentCall.args[1](
|
||||
mockEvent,
|
||||
'd',
|
||||
{ x: 300, y: 100 }
|
||||
);
|
||||
|
||||
var childObj = mockDomainObject("d");
|
||||
var testElement = $("<div data-layout-id='some-id'></div>");
|
||||
$element.append(testElement);
|
||||
spyOn(testElement[0], 'click');
|
||||
|
||||
controller.selectIfNew('some-id', childObj);
|
||||
jasmine.Clock.tick(0);
|
||||
|
||||
expect(testElement[0].click).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
{
|
||||
"key": "ListViewController",
|
||||
"implementation": ListViewController,
|
||||
"depends": ["$scope", "formatService"]
|
||||
"depends": ["$scope"]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(function () {
|
||||
function ListViewController($scope, formatService) {
|
||||
function ListViewController($scope) {
|
||||
this.$scope = $scope;
|
||||
$scope.orderByField = 'title';
|
||||
$scope.reverseSort = false;
|
||||
@@ -30,8 +30,6 @@ define(function () {
|
||||
var unlisten = $scope.domainObject.getCapability('mutation')
|
||||
.listen(this.updateView.bind(this));
|
||||
|
||||
this.utc = formatService.getFormat('utc');
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
unlisten();
|
||||
});
|
||||
@@ -52,13 +50,17 @@ define(function () {
|
||||
icon: child.getCapability('type').getCssClass(),
|
||||
title: child.getModel().name,
|
||||
type: child.getCapability('type').getName(),
|
||||
persisted: this.utc.format(child.getModel().persisted),
|
||||
modified: this.utc.format(child.getModel().modified),
|
||||
persisted: new Date(
|
||||
child.getModel().persisted
|
||||
).toUTCString(),
|
||||
modified: new Date(
|
||||
child.getModel().modified
|
||||
).toUTCString(),
|
||||
asDomainObject: child,
|
||||
location: child.getCapability('location'),
|
||||
action: child.getCapability('action')
|
||||
};
|
||||
}, this);
|
||||
});
|
||||
};
|
||||
|
||||
return ListViewController;
|
||||
|
||||
@@ -31,9 +31,7 @@ define(
|
||||
controller,
|
||||
childModel,
|
||||
typeCapability,
|
||||
mutationCapability,
|
||||
formatService;
|
||||
|
||||
mutationCapability;
|
||||
beforeEach(function () {
|
||||
unlistenFunc = jasmine.createSpy("unlisten");
|
||||
|
||||
@@ -43,18 +41,6 @@ define(
|
||||
);
|
||||
mutationCapability.listen.andReturn(unlistenFunc);
|
||||
|
||||
formatService = jasmine.createSpyObj(
|
||||
"formatService",
|
||||
["getFormat"]
|
||||
);
|
||||
formatService.getFormat.andReturn(jasmine.createSpyObj(
|
||||
'utc',
|
||||
["format"]
|
||||
));
|
||||
formatService.getFormat().format.andCallFake(function (v) {
|
||||
return "formatted " + v;
|
||||
});
|
||||
|
||||
typeCapability = jasmine.createSpyObj(
|
||||
"typeCapability",
|
||||
["getCssClass", "getName"]
|
||||
@@ -108,27 +94,20 @@ define(
|
||||
);
|
||||
scope.domainObject = domainObject;
|
||||
|
||||
controller = new ListViewController(scope, formatService);
|
||||
controller = new ListViewController(scope);
|
||||
|
||||
waitsFor(function () {
|
||||
return scope.children;
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the UTC time format", function () {
|
||||
expect(formatService.getFormat).toHaveBeenCalledWith('utc');
|
||||
});
|
||||
|
||||
it("updates the view", function () {
|
||||
expect(scope.children[0]).toEqual(
|
||||
{
|
||||
icon: "icon-folder",
|
||||
title: "Battery Charge Status",
|
||||
type: "Folder",
|
||||
persisted: formatService.getFormat('utc')
|
||||
.format(childModel.persisted),
|
||||
modified: formatService.getFormat('utc')
|
||||
.format(childModel.modified),
|
||||
persisted: "Wed, 07 Jun 2017 20:34:57 GMT",
|
||||
modified: "Wed, 07 Jun 2017 20:34:57 GMT",
|
||||
asDomainObject: childObject,
|
||||
location: ''
|
||||
}
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
define([
|
||||
"legacyRegistry",
|
||||
"./src/controllers/NotebookController",
|
||||
"./src/controllers/NewEntryController",
|
||||
"./src/controllers/SelectSnapshotController",
|
||||
"./src/controllers/LayoutNotebookController",
|
||||
"./src/directives/MCTSnapshot",
|
||||
"./src/directives/MCTModalNotebook",
|
||||
"./src/directives/EntryDnd",
|
||||
"./src/actions/ViewSnapshot",
|
||||
"./src/actions/AnnotateSnapshot",
|
||||
"./src/actions/RemoveEmbed",
|
||||
"./src/actions/CreateSnapshot",
|
||||
"./src/actions/RemoveSnapshot",
|
||||
"./src/actions/NewEntryContextual",
|
||||
"./src/capabilities/NotebookCapability",
|
||||
"./src/policies/CompositionPolicy",
|
||||
"./src/policies/ViewPolicy"
|
||||
|
||||
], function (
|
||||
legacyRegistry,
|
||||
NotebookController,
|
||||
NewEntryController,
|
||||
SelectSnapshotController,
|
||||
LayoutNotebookController,
|
||||
MCTSnapshot,
|
||||
MCTModalNotebook,
|
||||
MCTEntryDnd,
|
||||
ViewSnapshotAction,
|
||||
AnnotateSnapshotAction,
|
||||
RemoveEmbedAction,
|
||||
CreateSnapshotAction,
|
||||
RemoveSnapshotAction,
|
||||
newEntryAction,
|
||||
NotebookCapability,
|
||||
CompositionPolicy,
|
||||
ViewPolicy
|
||||
) {
|
||||
legacyRegistry.register("platform/features/notebook", {
|
||||
"name": "Notebook Plugin",
|
||||
"description": "Create and save timestamped notes with embedded object snapshots.",
|
||||
"extensions":
|
||||
{
|
||||
"types": [
|
||||
{
|
||||
"key": "notebook",
|
||||
"name": "Notebook",
|
||||
"cssClass": "icon-notebook",
|
||||
"description": "Create and save timestamped notes with embedded object snapshots.",
|
||||
"features": ["creation"],
|
||||
"model": {
|
||||
"entries": [],
|
||||
"composition": [],
|
||||
"entryTypes": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"views": [
|
||||
{
|
||||
"key": "notebook.view",
|
||||
"type": "notebook",
|
||||
"cssClass": "icon-notebook",
|
||||
"name": "notebook",
|
||||
"templateUrl": "templates/notebook.html",
|
||||
"editable": false,
|
||||
"uses": [
|
||||
"composition",
|
||||
"action"
|
||||
],
|
||||
"gestures": [
|
||||
"drop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "layoutNotebook",
|
||||
"name": "Display Layout",
|
||||
"cssClass": "icon-layout",
|
||||
"type": "layout",
|
||||
"templateUrl": "templates/layoutNotebook.html",
|
||||
"editable": true,
|
||||
"uses": [],
|
||||
"toolbar": {
|
||||
"sections": [
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"method": "showFrame",
|
||||
"cssClass": "icon-frame-show",
|
||||
"control": "button",
|
||||
"title": "Show frame",
|
||||
"description": "Show frame"
|
||||
},
|
||||
{
|
||||
"method": "hideFrame",
|
||||
"cssClass": "icon-frame-hide",
|
||||
"control": "button",
|
||||
"title": "Hide frame",
|
||||
"description": "Hide frame"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "NotebookController",
|
||||
"implementation": NotebookController,
|
||||
"depends": ["$scope",
|
||||
"dialogService",
|
||||
"popupService",
|
||||
"agentService",
|
||||
"objectService",
|
||||
"navigationService",
|
||||
"now",
|
||||
"actionService",
|
||||
"$timeout",
|
||||
"$element"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "NewEntryController",
|
||||
"implementation": NewEntryController,
|
||||
"depends": ["$scope",
|
||||
"$rootScope"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "selectSnapshotController",
|
||||
"implementation": SelectSnapshotController,
|
||||
"depends": ["$scope",
|
||||
"$rootScope"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "LayoutNotebookController",
|
||||
"implementation": LayoutNotebookController,
|
||||
"depends": ["$scope"]
|
||||
}
|
||||
],
|
||||
"representations": [
|
||||
{
|
||||
"key": "draggedEntry",
|
||||
"templateUrl": "templates/entry.html"
|
||||
},
|
||||
{
|
||||
"key": "frameLayoutNotebook",
|
||||
"templateUrl": "templates/frameLayoutNotebook.html"
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"key": "annotate-snapshot",
|
||||
"templateUrl": "templates/annotation.html"
|
||||
},
|
||||
{
|
||||
"key": "notificationTemplate",
|
||||
"templateUrl": "templates/notifications.html"
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctSnapshot",
|
||||
"implementation": MCTSnapshot,
|
||||
"depends": [
|
||||
"$rootScope",
|
||||
"$document",
|
||||
"exportImageService",
|
||||
"dialogService",
|
||||
"notificationService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "mctEntryDnd",
|
||||
"implementation": MCTEntryDnd,
|
||||
"depends": [
|
||||
"$rootScope",
|
||||
"$compile",
|
||||
"dndService",
|
||||
"typeService",
|
||||
"notificationService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "mctModalNotebook",
|
||||
"implementation": MCTModalNotebook,
|
||||
"depends": [
|
||||
"$document"
|
||||
]
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"key": "view-snapshot",
|
||||
"implementation": ViewSnapshotAction,
|
||||
"name": "View Snapshot",
|
||||
"description": "View the large image in a modal",
|
||||
"category": "embed",
|
||||
"depends": [
|
||||
"$compile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "annotate-snapshot",
|
||||
"implementation": AnnotateSnapshotAction,
|
||||
"name": "Annotate Snapshot",
|
||||
"cssClass": "icon-pencil labeled",
|
||||
"description": "Annotate embed's snapshot",
|
||||
"category": "embed",
|
||||
"depends": [
|
||||
"dialogService",
|
||||
"dndService",
|
||||
"$rootScope"
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"key": "remove-embed",
|
||||
"implementation": RemoveEmbedAction,
|
||||
"name": "Remove...",
|
||||
"cssClass": "icon-trash labeled",
|
||||
"description": "Remove this embed",
|
||||
"category": [
|
||||
"embed",
|
||||
"embed-no-snap"
|
||||
],
|
||||
"depends": [
|
||||
"dialogService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "remove-snapshot",
|
||||
"implementation": RemoveSnapshotAction,
|
||||
"name": "Remove Snapshot",
|
||||
"cssClass": "icon-trash labeled",
|
||||
"description": "Remove Snapshot of the embed",
|
||||
"category": "embed",
|
||||
"depends": [
|
||||
"dialogService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "create-snapshot",
|
||||
"implementation": CreateSnapshotAction,
|
||||
"name": "Create Snapshot",
|
||||
"description": "Create a snapshot for the embed",
|
||||
"category": "embed-no-snap",
|
||||
"priority": "preferred",
|
||||
"depends": [
|
||||
"$compile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "notebook-new-entry",
|
||||
"implementation": newEntryAction,
|
||||
"name": "New Notebook Entry",
|
||||
"cssClass": "icon-notebook labeled",
|
||||
"description": "Add a new entry",
|
||||
"category": [
|
||||
"contextual",
|
||||
"view-control"
|
||||
],
|
||||
"depends": [
|
||||
"$compile",
|
||||
"$rootScope",
|
||||
"dialogService",
|
||||
"notificationService",
|
||||
"linkService"
|
||||
],
|
||||
"priority": "preferred"
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
{
|
||||
"name": "painterro",
|
||||
"version": "4.1.0",
|
||||
"author": "Mike Bostock",
|
||||
"description": "D3 (or D3.js) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.",
|
||||
"website": "https://d3js.org/",
|
||||
"copyright": "Copyright 2010-2016 Mike Bostock",
|
||||
"license": "BSD-3-Clause",
|
||||
"link": "https://github.com/d3/d3/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"capabilities": [
|
||||
{
|
||||
"key": "notebook",
|
||||
"name": "Notebook Capability",
|
||||
"description": "Provides a capability for looking for a notebook domain object",
|
||||
"implementation": NotebookCapability,
|
||||
"depends": [
|
||||
"typeService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"category": "composition",
|
||||
"implementation": CompositionPolicy,
|
||||
"message": "Objects of this type cannot contain objects of that type."
|
||||
},
|
||||
{
|
||||
"category": "view",
|
||||
"implementation": ViewPolicy
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"key": "embed-control",
|
||||
"templateUrl": "templates/controls/embedControl.html"
|
||||
},
|
||||
{
|
||||
"key": "snapshot-select",
|
||||
"templateUrl": "templates/controls/snapSelect.html"
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "css/notebook.css",
|
||||
"theme": "espresso"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,414 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.mct-notebook{
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
div.example-button-group {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.example-button-group a {
|
||||
padding: 3px;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.example-button-group a.selected {
|
||||
border: 1px gray solid;
|
||||
border-radius: 3px;
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.example-task-completed .example-task-description {
|
||||
text-decoration: line-through;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.example-task-description.selected {
|
||||
background: #46A;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.example-message {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.notebook-new-entry{
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.drag-area{
|
||||
border: 2px dashed #006080;
|
||||
border-radius: 5px;
|
||||
padding: 10px 0;
|
||||
margin: 15px 0;
|
||||
font-style: italic;
|
||||
cursor: pointer;
|
||||
&.drag-active{
|
||||
border: 2px dashed $colorKey;
|
||||
}
|
||||
.glyph{
|
||||
flex: 1 1 0;
|
||||
&:before{
|
||||
left:10px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
p{
|
||||
flex: 4 1 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.frame{
|
||||
.icon-notebook{
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay.l-dialog .title{
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.entries-wrapper{
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: scroll;
|
||||
height: calc(100% - 92px);
|
||||
.entries-list{
|
||||
.entry{
|
||||
border-bottom: 1px solid #999;
|
||||
padding: 10px 0;
|
||||
&:first-child{
|
||||
border-top: 1px solid #999;
|
||||
}
|
||||
&.active,&:hover{
|
||||
background-color: rgba(0, 153, 204, 0.2);
|
||||
.entry-info .entry-text{
|
||||
.unedited-text{
|
||||
display: none;
|
||||
}
|
||||
textarea{
|
||||
background-color: $colorBodyBg;
|
||||
min-height: 50px;
|
||||
height: auto;
|
||||
resize: none;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.entry-time{
|
||||
flex: 1 1 0;
|
||||
text-align: center;
|
||||
}
|
||||
.entry-info{
|
||||
flex: 4 1 0;
|
||||
padding: 0 15px;
|
||||
min-height: 65px;
|
||||
.embeds{
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.snap-thumb,.embed-icon{
|
||||
cursor: pointer;
|
||||
}
|
||||
.entry-text{
|
||||
min-height: 50px;
|
||||
margin-bottom:15px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
.unedited-text{
|
||||
margin: 0;
|
||||
min-height: 50px;
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
textarea{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.entry-embedded{
|
||||
margin-right: 20px;
|
||||
height: 100px;
|
||||
position: relative;
|
||||
margin-bottom: 20px
|
||||
|
||||
}
|
||||
}
|
||||
.entry-delete{
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.embed{
|
||||
.embed-info{
|
||||
.embed-title{
|
||||
z-index: 99;
|
||||
text-transform: uppercase;
|
||||
max-width: 200px;
|
||||
}
|
||||
.embed-date{
|
||||
font-size: 14px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
.embed-icon{
|
||||
margin: 10px;
|
||||
position: absolute;
|
||||
}
|
||||
.btn-annotate{
|
||||
margin: 0 15px;
|
||||
z-index: 3;
|
||||
}
|
||||
&.nosnapshot{
|
||||
.embed-icon{
|
||||
margin: 2px;
|
||||
cursor: initial;
|
||||
}
|
||||
.embed-info{
|
||||
padding-left: 25px;
|
||||
}
|
||||
.embed-title{
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.snapshot{
|
||||
z-index: -9999;
|
||||
background: $colorBodyBg;
|
||||
}
|
||||
|
||||
.t-contents,.snap-annotation{
|
||||
overflow: hidden;
|
||||
img{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.snap-thumb{
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #999;
|
||||
margin-right: 15px;
|
||||
img{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.notebook-filters{
|
||||
.select{
|
||||
margin-left: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.embed-info{
|
||||
.embed-title{
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.user-folders{
|
||||
border-top: 1px solid #999;
|
||||
padding-top: 10px;
|
||||
.t-item-icon{
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.options-menu-container{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
|
||||
.embed-option{
|
||||
box-sizing: border-box;
|
||||
border-top: 1px solid #878787;
|
||||
color: white;
|
||||
line-height: 1.5rem;
|
||||
padding: 3px 10px 3px 28px;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
display: list-item;
|
||||
&:first-child{
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.new-display-embed{
|
||||
font-size: 14px;
|
||||
.nosnapshot{
|
||||
.embed-icon{
|
||||
margin: 2px;
|
||||
}
|
||||
.embed-info{
|
||||
padding-left: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.view-header{
|
||||
.view-date{
|
||||
float: right;
|
||||
}
|
||||
.view-snap-info{
|
||||
float: left;
|
||||
}
|
||||
.s-button{
|
||||
clear: both;
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.view-info{
|
||||
float: left;
|
||||
.embed-icon{
|
||||
display: inline-block;
|
||||
}
|
||||
.embed-title{
|
||||
display: inline-block;
|
||||
margin: 0 5px 0 10px;
|
||||
}
|
||||
.object-header{
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.context-available{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.menu-element.menu-view{
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.new-notebook-entry{
|
||||
float: left;
|
||||
.title-label{
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.notebook-button-container{
|
||||
position: absolute;
|
||||
top:30px;
|
||||
}
|
||||
|
||||
.container-notebook{
|
||||
top:64px;
|
||||
height: calc(100% - 30px);
|
||||
}
|
||||
|
||||
.ptro-color-main{
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
height: auto;
|
||||
min-height: 41px;
|
||||
}
|
||||
|
||||
.ptro-wrapper{
|
||||
bottom: 0;
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
.overlay.l-dialog .abs.editor{
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.overlay.l-dialog .outer-holder.annotation-dialog{
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.snap-annotation-wrapper{
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.annotate-new{
|
||||
.s-button{
|
||||
margin-left: 25px;
|
||||
margin-top: 10px;
|
||||
z-index: 9;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px){
|
||||
.entries-wrapper{
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.l-message{
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
.type-icon.message-type{
|
||||
margin: 0 auto 40px;
|
||||
}
|
||||
|
||||
.top-bar .title{
|
||||
text-align: center;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.ptro-color-main{
|
||||
height: 80px;
|
||||
.tool-controls,>div>span:not(.ptro-info){
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.ptro-wrapper{
|
||||
top: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px){
|
||||
.ptro-bar>div {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
$output-bourbon-deprecation-warnings: false;
|
||||
@import "bourbon";
|
||||
@import "../../../../platform/commonUI/general/res/sass/constants";
|
||||
@import "../../../../platform/commonUI/general/res/sass/mixins";
|
||||
@import "../../../../platform/commonUI/themes/espresso/res/sass/constants";
|
||||
@import "../../../../platform/commonUI/themes/espresso/res/sass/mixins";
|
||||
|
||||
// Thematic constants
|
||||
$colorCode: rgba(black, 0.2);
|
||||
$colorGlyphExample: #fff;
|
||||
|
||||
@import "notebook-base";
|
||||
|
||||
div.themed.espresso { display: block; }
|
||||
span.themed.espresso { display: inline; }
|
||||
@@ -1,2 +0,0 @@
|
||||
<div class="snap-annotation" id="snap-annotation" ng-init="ngModel.tracker()">
|
||||
</div>
|
||||
@@ -1,57 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class='form-control'>
|
||||
<ng-form name="mctControl">
|
||||
<div class='fields' ng-controller="NewEntryController">
|
||||
<div class="l-flex-row new-display-embed">
|
||||
<div class="l-flex-row embed">
|
||||
<div ng-if="snapToggle" class="l-flex-row">
|
||||
<div class="snap-thumb l-flex-row">
|
||||
<div ng-class="cssClass" class="abs embed-icon"></div>
|
||||
<img ng-src="{{snapshot.src}}" alt="{{snapshot.modified}}" >
|
||||
</div>
|
||||
<div class="embed-info l-flex-col">
|
||||
<div class="embed-title">{{objectName}}</div>
|
||||
<div class="embed-date">{{snapshot.modified| date:'yyyy-MM-dd HH:mm:ss'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="!snapToggle" class="l-flex-row nosnapshot">
|
||||
<div class="l-flex-row">
|
||||
<span ng-class="cssClass" class="abs embed-icon"></span>
|
||||
<div class="embed-info">
|
||||
<span class="embed-title">{{objectName}}</span>
|
||||
<span class="embed-date">{{snapshot.modified| date:'yyyy-MM-dd HH:mm:ss'}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="l-flex-row embed annotate-new" ng-if="snapToggle">
|
||||
<a class="s-button icon-pencil" title="Edit" ng-click="annotateSnapshot()">
|
||||
<span class="title-label">Annotate</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
@@ -1,30 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class='form-control select' ng-controller="selectSnapshotController">
|
||||
<select
|
||||
ng-model="selectModel"
|
||||
ng-options="opt.value as opt.name for opt in options"
|
||||
ng-required="ngRequired"
|
||||
name="mctControl">
|
||||
<!-- <option value="" ng-show="!ngModel[field]">- Select One -</option> -->
|
||||
</select>
|
||||
</div>
|
||||
@@ -1,38 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="frame snap-frame frame-template t-frame-inner abs t-object-type-{{ representation.selected.key }}">
|
||||
<div class="abs object-browse-bar l-flex-row">
|
||||
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
|
||||
<mct-representation
|
||||
key="'switcher'"
|
||||
ng-model="representation"
|
||||
mct-object="domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
<div class="abs object-holder" data-entry = "{{parameters.entry}}" data-embed = "{{parameters.embed}}" mct-snapshot ng-if="representation.selected.key">
|
||||
<mct-representation
|
||||
key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,54 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="frame frame-template t-frame-inner abs t-object-type-{{ representation.selected.key }}">
|
||||
<div class="abs object-browse-bar l-flex-row">
|
||||
<div class="left flex-elem l-flex-row grows">
|
||||
<mct-representation
|
||||
key="'object-header-frame'"
|
||||
mct-object="domainObject"
|
||||
class="l-flex-row flex-elem object-header grows">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
|
||||
<mct-representation
|
||||
key="'switcher'"
|
||||
ng-model="representation"
|
||||
mct-object="domainObject">
|
||||
</mct-representation>
|
||||
<a class="s-button icon-notebook t-btn-view-large"
|
||||
title="New Notebook Entry"
|
||||
ng-if="parameters"
|
||||
ng-click="ngModel()">
|
||||
</a>
|
||||
<a class="s-button icon-expand t-btn-view-large"
|
||||
title="View large"
|
||||
mct-modal-notebook>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="abs object-holder">
|
||||
<mct-representation
|
||||
key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,84 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<div class="abs l-layout"
|
||||
ng-controller="LayoutController as controller"
|
||||
ng-click="controller.clearSelection()">
|
||||
|
||||
<!-- Background grid -->
|
||||
<div class="l-grid-holder" ng-click="controller.clearSelection()">
|
||||
<div class="l-grid l-grid-x"
|
||||
ng-if="!controller.getGridSize()[0] < 3"
|
||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
||||
<div class="l-grid l-grid-y"
|
||||
ng-if="!controller.getGridSize()[1] < 3"
|
||||
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
||||
</div>
|
||||
|
||||
<div class='abs frame t-frame-outer child-frame panel s-selectable s-moveable s-hover-border'
|
||||
ng-class="{ 'no-frame': !controller.hasFrame(childObject), 's-selected':controller.selected(childObject) }"
|
||||
ng-repeat="childObject in composition"
|
||||
ng-click="controller.select($event, childObject.getId())"
|
||||
ng-style="controller.getFrameStyle(childObject.getId())">
|
||||
|
||||
<div ng-controller="LayoutNotebookController as controller">
|
||||
<mct-representation key="'frameLayoutNotebook'"
|
||||
class="t-rep-frame holder contents abs"
|
||||
parameters = "hasNotebookAction"
|
||||
ng-model="newNotebook"
|
||||
mct-object="childObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
|
||||
<!-- Drag handles -->
|
||||
<span class="abs t-edit-handle-holder s-hover-border" ng-if="controller.selected(childObject)">
|
||||
<span class="edit-handle edit-move"
|
||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [0,0])"
|
||||
mct-drag="controller.continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag()">
|
||||
</span>
|
||||
|
||||
<span class="edit-corner edit-resize-nw"
|
||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [-1,-1])"
|
||||
mct-drag="controller.continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag()">
|
||||
</span>
|
||||
<span class="edit-corner edit-resize-ne"
|
||||
mct-drag-down="controller.startDrag(childObject.getId(), [0,1], [1,-1])"
|
||||
mct-drag="controller.continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag()">
|
||||
</span>
|
||||
<span class="edit-corner edit-resize-sw"
|
||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,0], [-1,1])"
|
||||
mct-drag="controller.continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag()">
|
||||
</span>
|
||||
<span class="edit-corner edit-resize-se"
|
||||
mct-drag-down="controller.startDrag(childObject.getId(), [0,0], [1,1])"
|
||||
mct-drag="controller.continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag()">
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,122 +0,0 @@
|
||||
<div ng-controller="NotebookController as controller" class="mct-notebook">
|
||||
|
||||
<!-- Reuse of native styles the more as I can -->
|
||||
<div class="notebook-head l-flex-row flex-elem grows">
|
||||
<div class="l-flex-row holder holder-search">
|
||||
|
||||
<div class="search-bar flex-elem l-flex-row"
|
||||
ng-class="{ holder: !(entrySearch === '' || entrySearch === undefined) }">
|
||||
<div class="holder flex-elem grows">
|
||||
<input class="search-input"
|
||||
type="text" tabindex="10000"
|
||||
ng-model="entrySearch"
|
||||
ng-keyup="controller.search()"/>
|
||||
<a class="clear-icon clear-input icon-x-in-circle"
|
||||
ng-class="{show: !(entrySearch === '' || entrySearch === undefined)}"
|
||||
ng-click="entrySearch = ''; controller.search()"></a>
|
||||
</div>
|
||||
|
||||
<a class="holder s-button flex-elem btn-cancel"
|
||||
ng-show="!(entrySearch === '' || entrySearch === undefined)"
|
||||
ng-click="entrySearch = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()">
|
||||
Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="notebook-filters right l-flex-row flex-elem grows flex-justify-end">
|
||||
<div class="select">
|
||||
<select ng-model="showTime">
|
||||
<option value="0" selected="selected">Show all</option>
|
||||
<option value="1">Last Hour</option>
|
||||
<option value="8">Last 8 Hours</option>
|
||||
<option value="24">Last 24 Hours</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="select">
|
||||
<select ng-model="sortEntries">
|
||||
<option value="-createdOn" selected="selected">Newest first</option>
|
||||
<option value="createdOn">Oldest first</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- drag area -->
|
||||
|
||||
<div class="drag-area l-flex-row" ng-click="newEntry($event)" id="newEntry" mct-entry-dnd>
|
||||
<div class="glyph icon-plus" title="new"></div>
|
||||
<p>To start a new entry, click here or drag and drop any object</p>
|
||||
</div>
|
||||
|
||||
<!-- entries -->
|
||||
|
||||
<div class="entries-wrapper" ng-mouseover="handleActive()">
|
||||
<ul class="entries-list">
|
||||
<li class="entry l-flex-row" id="{{'entry_'+entry.createdOn}}" ng-if="hoursFilter(showTime,entry.createdOn)" ng-repeat="entry in model.entries | filter:entrySearch | orderBy: sortEntries track by $index" ng-init="$last && finished(model.entries)" mct-entry-dnd>
|
||||
<div class="entry-time">{{entry.createdOn | date:'yyyy-MM-dd HH:mm:ss'}}</div>
|
||||
<div class="entry-info">
|
||||
<div class="entry-text">
|
||||
<div class="unedited-text">
|
||||
<p ng-repeat="line in parseText(entry.text) track by $index">
|
||||
{{line}}
|
||||
</p>
|
||||
</div>
|
||||
<textarea ng-blur="textBlur($event,entry.createdOn)" ng-focus="textFocus($event)" ng-model="entry.text" placeholder="Enter text here" class="sm" rows="{{parseText(entry.text).length}}">{{entry.text}}</textarea>
|
||||
</div>
|
||||
<!-- embeds -->
|
||||
<div class="embeds l-flex-row">
|
||||
<div class="entry-embedded" ng-repeat="embed in entry.embeds track by $index" id="{{embed.id}}">
|
||||
<div class="l-flex-row embed" ng-class="{ 'nosnapshot' : !embed.snapshot}">
|
||||
<div ng-class="embed.cssClass" class="embed-icon" ng-click="viewSnapshot($event,embed.snapshot.src,embed.id,entry.createdOn,this,embed)"></div>
|
||||
<div class="snap-thumb" ng-if="embed.snapshot" ng-click="viewSnapshot($event,embed.snapshot.src,embed.id,entry.createdOn,this,embed)">
|
||||
<img ng-src="{{embed.snapshot.src}}" src="//:0" alt="{{embed.id}}" >
|
||||
</div>
|
||||
<div class="embed-info l-flex-col">
|
||||
<div class="embed-title object-header">
|
||||
<a href="#" ng-click='navigate($event,embed.type)'>{{embed.name}}</a>
|
||||
<a href="#" class='context-available' ng-click='openMenu($event,embed.type)'></a>
|
||||
</div>
|
||||
|
||||
<div class="hide-menu" ng-show="false">
|
||||
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
||||
<div class="menu context-menu">
|
||||
<ul>
|
||||
<li ng-repeat="menu in menuEmbed"
|
||||
ng-click="menu.perform($event,embed.snapshot.src,embed.id,entry.createdOn,this,embed)"
|
||||
title="{{menu.getMetadata().description}}"
|
||||
class="{{menu.getMetadata().cssClass}}"
|
||||
ng-if="embed.snapshot">
|
||||
{{menu.getMetadata().name}}
|
||||
</li>
|
||||
<li ng-repeat="menu in menuEmbedNoSnap"
|
||||
ng-click="menu.perform($event,embed.snapshot.src,embed.id,entry.createdOn,this)"
|
||||
title="{{menu.getMetadata().description}}"
|
||||
class="{{menu.getMetadata().cssClass}}"
|
||||
ng-if="!embed.snapshot">
|
||||
{{menu.getMetadata().name}}
|
||||
</li>
|
||||
<li ng-repeat="menu in embedActions"
|
||||
ng-click="menu.perform()"
|
||||
title="{{menu.name}}"
|
||||
class="{{menu.cssClass}}">
|
||||
{{menu.name}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="embed-date">{{embed.id| date:'yyyy-MM-dd HH:mm:ss'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- delete entry -->
|
||||
<div class="entry-delete">
|
||||
<a class="s-icon-button icon-trash" title="Delete Entry" ng-click="deleteEntry($event)"></a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,8 +0,0 @@
|
||||
<span class="status block">
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<span class="status-indicator icon-bell"></span>
|
||||
<span class="label">
|
||||
Notifications
|
||||
</span>
|
||||
<span class="count"></span>
|
||||
</span>
|
||||
@@ -1,111 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Module defining viewSnapshot (Originally NewWindowAction). Created by vwoeltje on 11/18/14.
|
||||
*/
|
||||
define(
|
||||
["painterro", "zepto"],
|
||||
function (Painterro, $) {
|
||||
|
||||
var ANNOTATION_STRUCT = {
|
||||
title: "Annotate Snapshot",
|
||||
template: "annotate-snapshot",
|
||||
options: [{
|
||||
name: "OK",
|
||||
key: "ok",
|
||||
description: "save annotation"
|
||||
},
|
||||
{
|
||||
name: "Cancel",
|
||||
key: "cancel",
|
||||
description: "cancel editing"
|
||||
}]
|
||||
};
|
||||
|
||||
function AnnotateSnapshot(dialogService,dndService,$rootScope,context) {
|
||||
context = context || {};
|
||||
|
||||
// Choose the object to be opened into a new tab
|
||||
this.domainObject = context.selectedObject || context.domainObject;
|
||||
this.dialogService = dialogService;
|
||||
this.dndService = dndService;
|
||||
this.$rootScope = $rootScope;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
AnnotateSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId,$scope) {
|
||||
|
||||
var DOMAIN_OBJECT = this.domainObject;
|
||||
var ROOTSCOPE = this.$rootScope;
|
||||
|
||||
this.dialogService.getUserChoice(ANNOTATION_STRUCT)
|
||||
.then(saveNotes);
|
||||
|
||||
var painterro;
|
||||
|
||||
var tracker = function () {
|
||||
$(document.body).find('.l-dialog .outer-holder').addClass('annotation-dialog');
|
||||
painterro = Painterro({
|
||||
id: 'snap-annotation',
|
||||
backgroundFillColor: '#eee',
|
||||
hiddenTools: ['save', 'open', 'close','eraser'],
|
||||
saveHandler: function (image, done) {
|
||||
if (entryId && embedId) {
|
||||
var elementPos = DOMAIN_OBJECT.model.entries.map(function (x) {
|
||||
return x.createdOn;
|
||||
}).indexOf(entryId);
|
||||
var entryEmbeds = DOMAIN_OBJECT.model.entries[elementPos].embeds;
|
||||
var embedPos = entryEmbeds.map(function (x) {
|
||||
return x.id;
|
||||
}).indexOf(embedId);
|
||||
$scope.saveSnap(image.asBlob(), embedPos, elementPos);
|
||||
}else {
|
||||
ROOTSCOPE.snapshot = {'src': image.asDataURL('image/png'),
|
||||
'modified': Date.now()};
|
||||
}
|
||||
|
||||
done(true);
|
||||
}
|
||||
}).show(snapshot);
|
||||
|
||||
};
|
||||
|
||||
ANNOTATION_STRUCT.model = {'tracker': tracker};
|
||||
|
||||
|
||||
|
||||
function saveNotes(param) {
|
||||
if (param === 'ok') {
|
||||
painterro.save();
|
||||
}else {
|
||||
ROOTSCOPE.snapshot = "annotationCancelled";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return AnnotateSnapshot;
|
||||
}
|
||||
);
|
||||
@@ -1,65 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
var SNAPSHOT_TEMPLATE = '<mct-representation key="\'draggedEntry\'"' +
|
||||
'parameters="{entry:entryId,embed:embedId}"' +
|
||||
'class="t-rep-frame holder"' +
|
||||
'mct-object="selObj">' +
|
||||
'</mct-representation>';
|
||||
|
||||
function CreateSnapshot($compile,context) {
|
||||
context = context || {};
|
||||
this.domainObject = context.selectedObject || context.domainObject;
|
||||
this.context = context;
|
||||
this.$compile = $compile;
|
||||
}
|
||||
|
||||
|
||||
CreateSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId,$scope) {
|
||||
var compile = this.$compile;
|
||||
var model = this.domainObject.model;
|
||||
var elementPos = model.entries.map(function (x) {
|
||||
return x.createdOn;
|
||||
}).indexOf(entryId);
|
||||
var entryEmbeds = model.entries[elementPos].embeds;
|
||||
var embedPos = entryEmbeds.map(function (x) {
|
||||
return x.id;
|
||||
}).indexOf(embedId);
|
||||
var embedType = entryEmbeds[embedPos].type;
|
||||
|
||||
$scope.getDomainObj(embedType).then(function (resp) {
|
||||
if (entryId >= 0 && embedId >= 0) {
|
||||
$scope.selObj = resp[embedType];
|
||||
$scope.entryId = elementPos;
|
||||
$scope.embedId = embedPos;
|
||||
compile(SNAPSHOT_TEMPLATE)($scope);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return CreateSnapshot;
|
||||
}
|
||||
);
|
||||
@@ -1,191 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
var SNAPSHOT_TEMPLATE = '<mct-representation key="\'draggedEntry\'"' +
|
||||
'class="t-rep-frame holder"' +
|
||||
'mct-object="selObj">' +
|
||||
'</mct-representation>';
|
||||
|
||||
var NEW_TASK_FORM = {
|
||||
name: "Create a Notebook Entry",
|
||||
hint: "Please select one Notebook",
|
||||
sections: [{
|
||||
rows: [{
|
||||
name: 'Entry',
|
||||
key: 'entry',
|
||||
control: 'textarea',
|
||||
required: true,
|
||||
"cssClass": "l-textarea-sm"
|
||||
},
|
||||
{
|
||||
name: 'Embed Type',
|
||||
key: 'withSnapshot',
|
||||
control: 'snapshot-select',
|
||||
"options": [
|
||||
{
|
||||
"name": "Link and Snapshot",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Link only",
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Embed',
|
||||
key: 'embedObject',
|
||||
control: 'embed-control'
|
||||
},
|
||||
{
|
||||
name: 'Save in Notebook',
|
||||
key: 'saveNotebook',
|
||||
control: 'locator',
|
||||
validate: validateLocation
|
||||
}]
|
||||
}]
|
||||
};
|
||||
|
||||
function NewEntryContextual($compile,$rootScope,dialogService,notificationService,linkService,context) {
|
||||
context = context || {};
|
||||
this.domainObject = context.selectedObject || context.domainObject;
|
||||
this.dialogService = dialogService;
|
||||
this.notificationService = notificationService;
|
||||
this.linkService = linkService;
|
||||
this.$rootScope = $rootScope;
|
||||
this.$compile = $compile;
|
||||
}
|
||||
|
||||
function validateLocation(newParentObj) {
|
||||
return newParentObj.model.type === 'notebook';
|
||||
}
|
||||
|
||||
|
||||
NewEntryContextual.prototype.perform = function () {
|
||||
|
||||
var self = this;
|
||||
var domainObj = this.domainObject;
|
||||
var notification = this.notificationService;
|
||||
var dialogService = this.dialogService;
|
||||
var rootScope = this.$rootScope;
|
||||
rootScope.newEntryText = '';
|
||||
// Create the overlay element and add it to the document's body
|
||||
this.$rootScope.selObj = domainObj;
|
||||
this.$rootScope.selValue = "";
|
||||
var newScope = rootScope.$new();
|
||||
newScope.selObj = domainObj;
|
||||
newScope.selValue = "";
|
||||
this.$compile(SNAPSHOT_TEMPLATE)(newScope);
|
||||
//newScope.$destroy();
|
||||
|
||||
this.$rootScope.$watch("snapshot", setSnapshot);
|
||||
|
||||
function setSnapshot(value) {
|
||||
if (value === "annotationCancelled") {
|
||||
rootScope.snapshot = rootScope.lastValue;
|
||||
rootScope.lastValue = '';
|
||||
}else if (value && value !== rootScope.lastValue) {
|
||||
var overlayModel = {
|
||||
title: NEW_TASK_FORM.name,
|
||||
message: NEW_TASK_FORM.message,
|
||||
structure: NEW_TASK_FORM,
|
||||
value: {'entry': rootScope.newEntryText || ""}
|
||||
};
|
||||
|
||||
rootScope.currentDialog = overlayModel;
|
||||
|
||||
dialogService.getDialogResponse(
|
||||
"overlay-dialog",
|
||||
overlayModel,
|
||||
function () {
|
||||
return overlayModel.value;
|
||||
}
|
||||
).then(addNewEntry);
|
||||
|
||||
rootScope.lastValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
function addNewEntry(options) {
|
||||
options.selectedModel = options.embedObject.getModel();
|
||||
options.cssClass = options.embedObject.getCapability('type').typeDef.cssClass;
|
||||
if (self.$rootScope.snapshot) {
|
||||
options.snapshot = self.$rootScope.snapshot;
|
||||
self.$rootScope.snapshot = undefined;
|
||||
}else {
|
||||
options.snapshot = undefined;
|
||||
}
|
||||
|
||||
if (!options.withSnapshot) {
|
||||
options.snapshot = '';
|
||||
}
|
||||
|
||||
createSnap(options);
|
||||
}
|
||||
|
||||
function createSnap(options) {
|
||||
options.saveNotebook.useCapability('mutation', function (model) {
|
||||
var entries = model.entries;
|
||||
var lastEntry = entries[entries.length - 1];
|
||||
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
|
||||
model.entries.push({
|
||||
'createdOn': Date.now(),
|
||||
'text': options.entry,
|
||||
'embeds': [{'type': options.embedObject.getId(),
|
||||
'id': '' + Date.now(),
|
||||
'cssClass': options.cssClass,
|
||||
'name': options.selectedModel.name,
|
||||
'snapshot': options.snapshot
|
||||
}]
|
||||
});
|
||||
}else {
|
||||
model.entries[entries.length - 1] = {
|
||||
'createdOn': Date.now(),
|
||||
'text': options.entry,
|
||||
'embeds': [{'type': options.embedObject.getId(),
|
||||
'id': '' + Date.now(),
|
||||
'cssClass': options.cssClass,
|
||||
'name': options.selectedModel.name,
|
||||
'snapshot': options.snapshot
|
||||
}]
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
notification.info({
|
||||
title: "Notebook Entry created"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
NewEntryContextual.appliesTo = function (context) {
|
||||
var domainObject = context.domainObject;
|
||||
return domainObject && domainObject.hasCapability("notebook") &&
|
||||
domainObject.getCapability("notebook").isNotebook();
|
||||
};
|
||||
|
||||
return NewEntryContextual;
|
||||
}
|
||||
);
|
||||
@@ -1,72 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
function RemoveEmbed(dialogService,context) {
|
||||
context = context || {};
|
||||
|
||||
this.domainObject = context.selectedObject || context.domainObject;
|
||||
this.dialogService = dialogService;
|
||||
}
|
||||
|
||||
|
||||
RemoveEmbed.prototype.perform = function ($event,snapshot,embedId,entryId) {
|
||||
var DOMAIN_OBJ = this.domainObject;
|
||||
var errorDialog = this.dialogService.showBlockingMessage({
|
||||
severity: "error",
|
||||
title: "This action will permanently delete this Embed. Do you want to continue?",
|
||||
minimized: true, // want the notification to be minimized initially (don't show banner)
|
||||
options: [{
|
||||
label: "OK",
|
||||
callback: function () {
|
||||
errorDialog.dismiss();
|
||||
remove();
|
||||
}
|
||||
},{
|
||||
label: "Cancel",
|
||||
callback: function () {
|
||||
errorDialog.dismiss();
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
function remove() {
|
||||
DOMAIN_OBJ.useCapability('mutation', function (model) {
|
||||
var elementPos = model.entries.map(function (x) {
|
||||
return x.createdOn;
|
||||
}).indexOf(entryId);
|
||||
var entryEmbeds = model.entries[elementPos].embeds;
|
||||
var embedPos = entryEmbeds.map(function (x) {
|
||||
return x.id;
|
||||
}).indexOf(embedId);
|
||||
model.entries[elementPos].embeds.splice(embedPos, 1);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return RemoveEmbed;
|
||||
}
|
||||
);
|
||||
@@ -1,74 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
function RemoveSnapshot(dialogService,context) {
|
||||
context = context || {};
|
||||
|
||||
this.domainObject = context.selectedObject || context.domainObject;
|
||||
this.dialogService = dialogService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RemoveSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId) {
|
||||
|
||||
var DOMAIN_OBJ = this.domainObject;
|
||||
var errorDialog = this.dialogService.showBlockingMessage({
|
||||
severity: "error",
|
||||
title: "This action will permanently delete this Snapshot. Do you want to continue?",
|
||||
minimized: true, // want the notification to be minimized initially (don't show banner)
|
||||
options: [{
|
||||
label: "OK",
|
||||
callback: function () {
|
||||
errorDialog.dismiss();
|
||||
remove();
|
||||
}
|
||||
},{
|
||||
label: "Cancel",
|
||||
callback: function () {
|
||||
errorDialog.dismiss();
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
function remove() {
|
||||
DOMAIN_OBJ.useCapability('mutation', function (model) {
|
||||
var elementPos = model.entries.map(function (x) {
|
||||
return x.createdOn;
|
||||
}).indexOf(entryId);
|
||||
var entryEmbeds = model.entries[elementPos].embeds;
|
||||
var embedPos = entryEmbeds.map(function (x) {
|
||||
return x.id;
|
||||
}).indexOf(embedId);
|
||||
model.entries[elementPos].embeds[embedPos].snapshot = "";
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return RemoveSnapshot;
|
||||
}
|
||||
);
|
||||
@@ -1,160 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Module defining ViewSnapshot
|
||||
*/
|
||||
define(
|
||||
['zepto'],
|
||||
function ($) {
|
||||
|
||||
var OVERLAY_TEMPLATE = '' +
|
||||
' <div class="abs blocker"></div>' +
|
||||
' <div class="abs outer-holder">' +
|
||||
' <a class="close icon-x-in-circle"></a>' +
|
||||
' <div class="abs inner-holder l-flex-col">' +
|
||||
' <div class="t-contents flex-elem holder grows"></div>' +
|
||||
' <div class="bottom-bar flex-elem holder">' +
|
||||
' <a class="t-done s-button major">Done</a>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
' </div>';
|
||||
|
||||
var toggleOverlay,
|
||||
overlay,
|
||||
closeButton,
|
||||
doneButton,
|
||||
blocker,
|
||||
overlayContainer,
|
||||
img,
|
||||
annotateButton,
|
||||
annotateImg;
|
||||
|
||||
function ViewSnapshot($compile,context) {
|
||||
context = context || {};
|
||||
|
||||
this.$compile = $compile;
|
||||
}
|
||||
|
||||
function openOverlay(url,header) {
|
||||
overlay = document.createElement('div');
|
||||
$(overlay).addClass('abs overlay l-large-view');
|
||||
overlay.innerHTML = OVERLAY_TEMPLATE;
|
||||
overlayContainer = overlay.querySelector('.t-contents');
|
||||
closeButton = overlay.querySelector('a.close');
|
||||
closeButton.addEventListener('click', toggleOverlay);
|
||||
doneButton = overlay.querySelector('a.t-done');
|
||||
doneButton.addEventListener('click', toggleOverlay);
|
||||
blocker = overlay.querySelector('.abs.blocker');
|
||||
blocker.addEventListener('click', toggleOverlay);
|
||||
annotateButton = header.querySelector('a.icon-pencil');
|
||||
annotateButton.addEventListener('click', annotateImg);
|
||||
document.body.appendChild(overlay);
|
||||
img = document.createElement('img');
|
||||
img.src = url;
|
||||
overlayContainer.appendChild(header);
|
||||
overlayContainer.appendChild(img);
|
||||
}
|
||||
|
||||
function closeOverlay() {
|
||||
overlayContainer.removeChild(img);
|
||||
document.body.removeChild(overlay);
|
||||
closeButton.removeEventListener('click', toggleOverlay);
|
||||
closeButton = undefined;
|
||||
doneButton.removeEventListener('click', toggleOverlay);
|
||||
doneButton = undefined;
|
||||
blocker.removeEventListener('click', toggleOverlay);
|
||||
blocker = undefined;
|
||||
overlayContainer = undefined;
|
||||
overlay = undefined;
|
||||
img = undefined;
|
||||
}
|
||||
|
||||
function headerTemplate() {
|
||||
var template = '<div class="view-header">' +
|
||||
'<div class="view-info">' +
|
||||
'<div ng-class="cssClass" class="embed-icon"></div>' +
|
||||
'<div class="embed-title">{{entryName}}</div>' +
|
||||
'<div class="object-header">' +
|
||||
'<a href="" class="context-available" ng-click="openMenu($event,embedType)""></a>' +
|
||||
'</div>' +
|
||||
'<div class="hide-menu" ng-show="false">' +
|
||||
'<div class="menu-element menu-view context-menu-wrapper mobile-disable-select">' +
|
||||
'<div class="menu context-menu">' +
|
||||
'<ul>' +
|
||||
'<li ng-repeat="menu in embedActions"' +
|
||||
'ng-click="menu.perform()"' +
|
||||
'title="{{menu.name}}"' +
|
||||
'class="{{menu.cssClass}}">' +
|
||||
'{{menu.name}}' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="view-date">' +
|
||||
'<span class="icon-alert-rect" title="Snapshot">' +
|
||||
'</span> ' +
|
||||
'SNAPSHOT {{snapDate | date:\'yyyy-MM-dd HH:mm:ss\'}}' +
|
||||
'</div>' +
|
||||
'<a class="s-button icon-pencil" title="Annotate">' +
|
||||
'<span class="title-label">Annotate</span>' +
|
||||
'</a>' +
|
||||
'</div>';
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
ViewSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId,$scope,embed) {
|
||||
var isOpen = false;
|
||||
|
||||
// Create the overlay element and add it to the document's body
|
||||
$scope.cssClass = embed.cssClass;
|
||||
$scope.embedType = embed.type;
|
||||
$scope.entryName = embed.name;
|
||||
$scope.snapDate = +embedId;
|
||||
var element = this.$compile(headerTemplate())($scope);
|
||||
|
||||
var annotateAction = $scope.action.getActions({category: 'embed'})[1];
|
||||
|
||||
toggleOverlay = function () {
|
||||
if (!isOpen) {
|
||||
openOverlay(snapshot, element[0]);
|
||||
isOpen = true;
|
||||
} else {
|
||||
closeOverlay();
|
||||
isOpen = false;
|
||||
}
|
||||
};
|
||||
|
||||
annotateImg = function () {
|
||||
closeOverlay();
|
||||
annotateAction.perform($event, snapshot, embedId, entryId, $scope);
|
||||
};
|
||||
|
||||
toggleOverlay();
|
||||
};
|
||||
|
||||
return ViewSnapshot;
|
||||
}
|
||||
);
|
||||
@@ -1,50 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
define(
|
||||
function () {
|
||||
|
||||
/**
|
||||
* The notebook capability allows a domain object to know whether the
|
||||
* notebook plugin is present or not.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function NotebookCapability(typeService, domainObject) {
|
||||
this.domainObject = domainObject;
|
||||
this.typeService = typeService;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is a notebook domain Object.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
NotebookCapability.prototype.isNotebook = function () {
|
||||
return this.typeService.getType('notebook');
|
||||
};
|
||||
|
||||
return NotebookCapability;
|
||||
}
|
||||
);
|
||||
@@ -1,54 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* This bundle implements object types and associated views for
|
||||
* display-building.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* The LayoutNotebookController is responsible for supporting the
|
||||
* notebook feature creation on theLayout view.
|
||||
**/
|
||||
|
||||
function LayoutNotebookController($scope) {
|
||||
$scope.hasNotebookAction = undefined;
|
||||
|
||||
$scope.newNotebook = undefined;
|
||||
|
||||
var actions = $scope.domainObject.getCapability('action');
|
||||
var notebookAction = actions.getActions({'key': 'notebook-new-entry'});
|
||||
if (notebookAction.length > 0) {
|
||||
$scope.hasNotebookAction = true;
|
||||
$scope.newNotebook = function () {
|
||||
notebookAction[0].perform();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return LayoutNotebookController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Module defining NewEntryController. */
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
function NewEntryController($scope,$rootScope) {
|
||||
|
||||
$scope.snapshot = undefined;
|
||||
$scope.snapToggle = true;
|
||||
$scope.entryText = '';
|
||||
var annotateAction = $rootScope.selObj.getCapability('action').getActions(
|
||||
{category: 'embed'})[1];
|
||||
|
||||
$scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = $rootScope.selObj;
|
||||
$scope.objectName = $rootScope.selObj.getModel().name;
|
||||
$scope.cssClass = $rootScope.selObj.getCapability('type').typeDef.cssClass;
|
||||
|
||||
$scope.annotateSnapshot = function ($event) {
|
||||
if ($rootScope.currentDialog.value) {
|
||||
$rootScope.newEntryText = $scope.$parent.$parent.ngModel.entry;
|
||||
$rootScope.currentDialog.cancel();
|
||||
annotateAction.perform($event, $rootScope.snapshot.src);
|
||||
$rootScope.currentDialog = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
function updateSnapshot(img) {
|
||||
$scope.snapshot = img;
|
||||
}
|
||||
// Update set of actions whenever the action capability
|
||||
// changes or becomes available.
|
||||
$rootScope.$watch("snapshot", updateSnapshot);
|
||||
|
||||
$rootScope.$watch("selValue", toggleEmbed);
|
||||
|
||||
function toggleEmbed(value) {
|
||||
$scope.snapToggle = value;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntryController;
|
||||
}
|
||||
);
|
||||
@@ -1,331 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*-- main controller file, here is the core functionality of the notebook plugin --*/
|
||||
|
||||
define(
|
||||
['zepto'],
|
||||
function ($) {
|
||||
|
||||
|
||||
function NotebookController(
|
||||
$scope,
|
||||
dialogService,
|
||||
popupService,
|
||||
agentService,
|
||||
objectService,
|
||||
navigationService,
|
||||
now,
|
||||
actionService,
|
||||
$timeout,
|
||||
$element
|
||||
) {
|
||||
|
||||
$scope.entriesEl = $(document.body).find('.entries-list');
|
||||
$scope.sortEntries = '-createdOn';
|
||||
$scope.showTime = "0";
|
||||
$scope.editEntry = false;
|
||||
$scope.entrySearch = '';
|
||||
$scope.entryTypes = [];
|
||||
$scope.embedActions = [];
|
||||
$scope.currentEntryValue = '';
|
||||
|
||||
/*--seconds in an hour--*/
|
||||
|
||||
var SECONDS_IN_AN_HOUR = 60 * 60 * 1000;
|
||||
|
||||
this.scope = $scope;
|
||||
|
||||
$scope.hoursFilter = function (hours,entryTime) {
|
||||
if (+hours) {
|
||||
return entryTime > (now() - SECONDS_IN_AN_HOUR * (+hours));
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.scrollToTop = function () {
|
||||
var entriesContainer = $scope.entriesEl.parent();
|
||||
entriesContainer[0].scrollTop = 0;
|
||||
};
|
||||
|
||||
/*--create a new entry--*/
|
||||
$scope.newEntry = function ($event) {
|
||||
$scope.scrollToTop();
|
||||
var entries = $scope.domainObject.model.entries;
|
||||
var lastEntry = entries[entries.length - 1];
|
||||
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries.push({'createdOn': now()});
|
||||
});
|
||||
|
||||
}else {
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries[entries.length - 1].createdOn = now();
|
||||
});
|
||||
}
|
||||
$scope.entrySearch = '';
|
||||
};
|
||||
|
||||
/*--delete an entry--*/
|
||||
$scope.deleteEntry = function ($event) {
|
||||
var delId = $event.currentTarget.parentElement.parentElement.id;
|
||||
var errorDialog = dialogService.showBlockingMessage({
|
||||
severity: "error",
|
||||
title: "This action will permanently delete this Notebook entry. Do you want to continue?",
|
||||
minimized: true, // want the notification to be minimized initially (don't show banner)
|
||||
options: [{
|
||||
label: "OK",
|
||||
callback: function () {
|
||||
errorDialog.dismiss();
|
||||
var elementPos = $scope.domainObject.model.entries.map(function (x) {
|
||||
return x.createdOn;
|
||||
}).indexOf(+delId.replace('entry_', ''));
|
||||
if (elementPos !== -1) {
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries.splice(elementPos, 1);
|
||||
});
|
||||
} else {
|
||||
window.console.log('delete error');
|
||||
}
|
||||
|
||||
}
|
||||
},{
|
||||
label: "Cancel",
|
||||
callback: function () {
|
||||
errorDialog.dismiss();
|
||||
}
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
$scope.textFocus = function ($event) {
|
||||
if ($event.currentTarget && $event.currentTarget.value) {
|
||||
$scope.currentEntryValue = $event.currentTarget.value;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.textBlur = function ($event,entryId) {
|
||||
if ($event.target && $event.target.value !== "") {
|
||||
var elementPos = $scope.domainObject.model.entries.map(function (x) {
|
||||
return x.createdOn;
|
||||
}).indexOf(+(entryId));
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries[elementPos].text = $event.target.value;
|
||||
if ($scope.currentEntryValue !== $event.target.value) {
|
||||
model.entries[elementPos].createdOn = now();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.finished = function (model) {
|
||||
var lastEntry = model[model.length - 1];
|
||||
if (!lastEntry.text) {
|
||||
var newEntry = $scope.entriesEl.find('#entry_' + lastEntry.createdOn).addClass('active');
|
||||
newEntry.find('textarea').focus();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.handleActive = function () {
|
||||
var newEntry = $scope.entriesEl.find('.active');
|
||||
if (newEntry) {
|
||||
newEntry.removeClass('active');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$scope.clearSearch = function () {
|
||||
$scope.entrySearch = '';
|
||||
};
|
||||
|
||||
$scope.viewSnapshot = function ($event,snapshot,embedId,entryId,$innerScope,domainObject) {
|
||||
var viewAction = $scope.action.getActions({category: 'embed'})[0];
|
||||
viewAction.perform($event, snapshot, embedId, entryId, $innerScope, domainObject);
|
||||
};
|
||||
|
||||
|
||||
$scope.parseText = function (text) {
|
||||
if (text) {
|
||||
return text.split(/\r\n|\r|\n/gi);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.renderImage = function (img) {
|
||||
return URL.createObjectURL(img);
|
||||
};
|
||||
|
||||
$scope.getDomainObj = function (id) {
|
||||
return objectService.getObjects([id]);
|
||||
};
|
||||
/*-----*/
|
||||
function refreshComp(change) {
|
||||
if (change && change.length) {
|
||||
change[0].getCapability('action').getActions({key: 'remove'})[0].perform();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.actionToMenuOption = function (action) {
|
||||
return {
|
||||
key: action.getMetadata().key,
|
||||
name: action.getMetadata().name,
|
||||
cssClass: action.getMetadata().cssClass,
|
||||
perform: action.perform
|
||||
};
|
||||
};
|
||||
|
||||
// Maintain all "conclude-editing" and "save" actions in the
|
||||
// present context.
|
||||
function updateActions() {
|
||||
$scope.menuEmbed = $scope.action ?
|
||||
$scope.action.getActions({category: 'embed'}) :
|
||||
[];
|
||||
|
||||
$scope.menuEmbedNoSnap = $scope.action ?
|
||||
$scope.action.getActions({category: 'embed-no-snap'}) :
|
||||
[];
|
||||
|
||||
$scope.menuActions = $scope.action ?
|
||||
$scope.action.getActions({key: 'window'}) :
|
||||
[];
|
||||
}
|
||||
|
||||
// Update set of actions whenever the action capability
|
||||
// changes or becomes available.
|
||||
$scope.$watch("action", updateActions);
|
||||
|
||||
$scope.navigate = function ($event,embedType) {
|
||||
if ($event) {
|
||||
$event.preventDefault();
|
||||
}
|
||||
$scope.getDomainObj(embedType).then(function (resp) {
|
||||
navigationService.setNavigation(resp[embedType]);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.saveSnap = function (url,embedPos,entryPos) {
|
||||
var snapshot = false;
|
||||
if (url) {
|
||||
if (embedPos !== -1 && entryPos !== -1) {
|
||||
var reader = new window.FileReader();
|
||||
reader.readAsDataURL(url);
|
||||
reader.onloadend = function () {
|
||||
snapshot = reader.result;
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
if (model.entries[entryPos]) {
|
||||
model.entries[entryPos].embeds[embedPos].snapshot = {'src': snapshot,
|
||||
'type': url.type,
|
||||
'size': url.size,
|
||||
'modified': Date.now()
|
||||
};
|
||||
model.entries[entryPos].embeds[embedPos].id = Date.now();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}else {
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries[entryPos].embeds[embedPos].snapshot = snapshot;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*---popups menu embeds----*/
|
||||
|
||||
function getEmbedActions(embedType) {
|
||||
if (!$scope.embedActions.length) {
|
||||
$scope.getDomainObj(embedType).then(function (resp) {
|
||||
$scope.embedActions = [];
|
||||
$scope.embedActions.push($scope.actionToMenuOption(
|
||||
$scope.action.getActions({key: 'window',selectedObject: resp[embedType]})[0]
|
||||
));
|
||||
$scope.embedActions.push({
|
||||
key: 'navigate',
|
||||
name: 'Go to Original',
|
||||
cssClass: '',
|
||||
perform: function () {
|
||||
$scope.navigate('', embedType);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.openMenu = function ($event,embedType) {
|
||||
$event.preventDefault();
|
||||
|
||||
getEmbedActions(embedType);
|
||||
|
||||
var body = $(document).find('body'),
|
||||
initiatingEvent = agentService.isMobile() ?
|
||||
'touchstart' : 'mousedown',
|
||||
dismissExistingMenu,
|
||||
menu,
|
||||
popup;
|
||||
|
||||
var container = $($event.currentTarget).parent().parent();
|
||||
|
||||
menu = container.find('.menu-element');
|
||||
|
||||
// Remove the context menu
|
||||
function dismiss() {
|
||||
container.find('.hide-menu').append(menu);
|
||||
body.off("mousedown", dismiss);
|
||||
dismissExistingMenu = undefined;
|
||||
$scope.embedActions = [];
|
||||
}
|
||||
|
||||
// Dismiss any menu which was already showing
|
||||
if (dismissExistingMenu) {
|
||||
dismissExistingMenu();
|
||||
}
|
||||
|
||||
// ...and record the presence of this menu.
|
||||
dismissExistingMenu = dismiss;
|
||||
|
||||
popup = popupService.display(menu, [$event.pageX,$event.pageY], {
|
||||
marginX: 0,
|
||||
marginY: -50
|
||||
});
|
||||
|
||||
// Stop propagation so that clicks or touches on the menu do not close the menu
|
||||
menu.on(initiatingEvent, function (event) {
|
||||
event.stopPropagation();
|
||||
$timeout(dismiss, 300);
|
||||
});
|
||||
|
||||
// Dismiss the menu when body is clicked/touched elsewhere
|
||||
// ('mousedown' because 'click' breaks left-click context menus)
|
||||
// ('touchstart' because 'touch' breaks context menus up)
|
||||
body.on(initiatingEvent, dismiss);
|
||||
|
||||
};
|
||||
|
||||
|
||||
$scope.$watchCollection("composition", refreshComp);
|
||||
|
||||
|
||||
$scope.$on('$destroy', function () {});
|
||||
}
|
||||
|
||||
return NotebookController;
|
||||
});
|
||||
@@ -1,44 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Module defining SelectSnapshotController. */
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
function SelectSnapshotController($scope,$rootScope) {
|
||||
|
||||
$scope.selectModel = true;
|
||||
|
||||
function selectprint(value) {
|
||||
$rootScope.selValue = value;
|
||||
$scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = value;
|
||||
}
|
||||
|
||||
$scope.$watch("selectModel", selectprint);
|
||||
|
||||
}
|
||||
|
||||
return SelectSnapshotController;
|
||||
}
|
||||
);
|
||||
@@ -1,140 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(['zepto'], function ($) {
|
||||
var SNAPSHOT_TEMPLATE = '<mct-representation key="\'draggedEntry\'"' +
|
||||
'parameters="{entry:entryId,embed:embedId}"' +
|
||||
'class="t-rep-frame holder"' +
|
||||
'mct-object="selObj">' +
|
||||
'</mct-representation>';
|
||||
|
||||
function EntryDnd($rootScope,$compile,dndService,typeService,notificationService) {
|
||||
|
||||
function link($scope, $element) {
|
||||
|
||||
function drop(e) {
|
||||
var selectedObject = dndService.getData('mct-domain-object');
|
||||
var selectedModel = selectedObject.getModel();
|
||||
var cssClass = selectedObject.getCapability('type').typeDef.cssClass;
|
||||
var entryId = -1;
|
||||
var embedId = -1;
|
||||
|
||||
$scope.clearSearch();
|
||||
if ($element[0].id === 'newEntry') {
|
||||
entryId = $scope.domainObject.model.entries.length;
|
||||
embedId = 0;
|
||||
var lastEntry = $scope.domainObject.model.entries[entryId - 1];
|
||||
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries.push({'createdOn': +Date.now(),
|
||||
'embeds': [{'type': selectedObject.getId(),
|
||||
'id': '' + Date.now(),
|
||||
'cssClass': cssClass,
|
||||
'name': selectedModel.name,
|
||||
'snapshot': ''
|
||||
}]
|
||||
});
|
||||
});
|
||||
}else {
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries[entryId - 1] =
|
||||
{'createdOn': +Date.now(),
|
||||
'embeds': [{'type': selectedObject.getId(),
|
||||
'id': '' + Date.now(),
|
||||
'cssClass': cssClass,
|
||||
'name': selectedModel.name,
|
||||
'snapshot': ''
|
||||
}]
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
$scope.scrollToTop();
|
||||
notificationService.info({
|
||||
title: "Notebook Entry created"
|
||||
});
|
||||
|
||||
}else {
|
||||
|
||||
entryId = $scope.domainObject.model.entries.map(function (x) {
|
||||
return x.createdOn;
|
||||
}).indexOf(+($element[0].id.replace('entry_', '')));
|
||||
if (!$scope.domainObject.model.entries[entryId].embeds) {
|
||||
$scope.domainObject.model.entries[entryId].embeds = [];
|
||||
}
|
||||
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
model.entries[entryId].embeds.push({'type': selectedObject.getId(),
|
||||
'id': '' + Date.now(),
|
||||
'cssClass': cssClass,
|
||||
'name': selectedModel.name,
|
||||
'snapshot': ''
|
||||
});
|
||||
});
|
||||
|
||||
embedId = $scope.domainObject.model.entries[entryId].embeds.length - 1;
|
||||
|
||||
if (selectedObject) {
|
||||
e.preventDefault();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (entryId >= 0 && embedId >= 0) {
|
||||
$scope.selObj = selectedObject;
|
||||
$scope.entryId = entryId;
|
||||
$scope.embedId = embedId;
|
||||
$compile(SNAPSHOT_TEMPLATE)($scope);
|
||||
}
|
||||
|
||||
if ($(e.currentTarget).hasClass('drag-active')) {
|
||||
$(e.currentTarget).removeClass('drag-active');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function dragover(e) {
|
||||
if (!$(e.currentTarget).hasClass('drag-active')) {
|
||||
$(e.currentTarget).addClass('drag-active');
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for the drop itself
|
||||
$element.on('dragover', dragover);
|
||||
$element.on('drop', drop);
|
||||
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$element.off('dragover', dragover);
|
||||
$element.off('drop', drop);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return EntryDnd;
|
||||
|
||||
});
|
||||
@@ -1,165 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'zepto'
|
||||
], function (
|
||||
$
|
||||
) {
|
||||
|
||||
var OVERLAY_TEMPLATE = '' +
|
||||
' <div class="abs blocker"></div>' +
|
||||
' <div class="abs outer-holder">' +
|
||||
' <a class="close icon-x-in-circle"></a>' +
|
||||
' <div class="abs inner-holder l-flex-col">' +
|
||||
' <div class="t-contents flex-elem holder grows"></div>' +
|
||||
' <div class="bottom-bar flex-elem holder">' +
|
||||
' <a class="t-done s-button major">Done</a>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
' </div>';
|
||||
|
||||
var NEW_NOTEBOOK_TEMPLATE = '<a class="s-button icon-notebook new-notebook-entry" title="New Notebook Entry">' +
|
||||
'<span class="title-label">New Notebook Entry</span>' +
|
||||
'</a>';
|
||||
|
||||
/**
|
||||
* MCT Trigger Modal is intended for use in only one location: inside the
|
||||
* object-header to allow views in a layout to be popped out in a modal.
|
||||
* Users can close the modal and go back to normal, and everything generally
|
||||
* just works fine.
|
||||
*
|
||||
* This code is sensitive to how our html is constructed-- particularly with
|
||||
* how it locates the the container of an element in a layout. However, it
|
||||
* should be able to handle slight relocations so long as it is always a
|
||||
* descendent of a `.frame` element.
|
||||
*/
|
||||
function MCTModalNotebook($document) {
|
||||
var document = $document[0];
|
||||
|
||||
function link($scope, $element) {
|
||||
var frame = $element.parent();
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
if (frame.hasClass('frame')) {
|
||||
break;
|
||||
}
|
||||
frame = frame.parent();
|
||||
}
|
||||
if (!frame.hasClass('frame')) {
|
||||
$element.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
frame = frame[0];
|
||||
var layoutContainer = frame.parentElement,
|
||||
isOpen = false,
|
||||
toggleOverlay,
|
||||
overlay,
|
||||
closeButton,
|
||||
doneButton,
|
||||
notebookButton,
|
||||
blocker,
|
||||
overlayContainer,
|
||||
notebookButtonEl;
|
||||
|
||||
function openOverlay() {
|
||||
|
||||
// Remove frame classes from being applied in a non-frame context
|
||||
$(frame).removeClass('frame frame-template');
|
||||
overlay = document.createElement('div');
|
||||
$(overlay).addClass('abs overlay l-large-view');
|
||||
overlay.innerHTML = OVERLAY_TEMPLATE;
|
||||
overlayContainer = overlay.querySelector('.t-contents');
|
||||
closeButton = overlay.querySelector('a.close');
|
||||
closeButton.addEventListener('click', toggleOverlay);
|
||||
doneButton = overlay.querySelector('a.t-done');
|
||||
doneButton.addEventListener('click', toggleOverlay);
|
||||
blocker = overlay.querySelector('.abs.blocker');
|
||||
blocker.addEventListener('click', toggleOverlay);
|
||||
document.body.appendChild(overlay);
|
||||
layoutContainer.removeChild(frame);
|
||||
overlayContainer.appendChild(frame);
|
||||
|
||||
//verify if there is a new notebook entry action
|
||||
var actions = $scope.domainObject.getCapability('action');
|
||||
var notebookAction = actions.getActions({'key': 'notebook-new-entry'});
|
||||
if (notebookAction.length > 0) {
|
||||
notebookButtonEl = document.createElement('div');
|
||||
$(notebookButtonEl).addClass('notebook-button-container');
|
||||
notebookButtonEl.innerHTML = NEW_NOTEBOOK_TEMPLATE;
|
||||
notebookButton = frame.querySelector('.object-browse-bar .left');
|
||||
notebookButton.appendChild(notebookButtonEl);
|
||||
$(frame.querySelector('.object-holder')).addClass('container-notebook');
|
||||
notebookButton.addEventListener('click', function () {
|
||||
notebookAction[0].perform();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function closeOverlay() {
|
||||
$(frame).addClass('frame frame-template');
|
||||
overlayContainer.removeChild(frame);
|
||||
layoutContainer.appendChild(frame);
|
||||
document.body.removeChild(overlay);
|
||||
closeButton.removeEventListener('click', toggleOverlay);
|
||||
closeButton = undefined;
|
||||
doneButton.removeEventListener('click', toggleOverlay);
|
||||
doneButton = undefined;
|
||||
blocker.removeEventListener('click', toggleOverlay);
|
||||
blocker = undefined;
|
||||
overlayContainer = undefined;
|
||||
overlay = undefined;
|
||||
|
||||
|
||||
if (notebookButton) {
|
||||
notebookButton.removeChild(notebookButtonEl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
toggleOverlay = function () {
|
||||
if (!isOpen) {
|
||||
openOverlay();
|
||||
isOpen = true;
|
||||
} else {
|
||||
closeOverlay();
|
||||
isOpen = false;
|
||||
}
|
||||
};
|
||||
|
||||
$element.on('click', toggleOverlay);
|
||||
$scope.$on('$destroy', function () {
|
||||
$element.off('click', toggleOverlay);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTModalNotebook;
|
||||
|
||||
});
|
||||
@@ -1,134 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(['zepto'], function ($) {
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
function MCTSnapshot($rootScope,$document,exportImageService,dialogService,notificationService) {
|
||||
var document = $document[0];
|
||||
|
||||
function link($scope, $element,$attrs) {
|
||||
var element = $element[0];
|
||||
var layoutContainer = element.parentElement,
|
||||
toggleOverlay,
|
||||
makeImg,
|
||||
saveImg,
|
||||
snapshot = document.createElement('div');
|
||||
|
||||
function openOverlay() {
|
||||
// Remove frame classes from being applied in a non-frame context
|
||||
$(snapshot).addClass('abs overlay l-large-view snapshot');
|
||||
snapshot.appendChild(element);
|
||||
document.body.appendChild(snapshot);
|
||||
}
|
||||
|
||||
function closeOverlay() {
|
||||
if (snapshot) {
|
||||
snapshot.removeChild(element);
|
||||
layoutContainer.remove();
|
||||
}
|
||||
document.body.removeChild(snapshot);
|
||||
snapshot = undefined;
|
||||
$element.remove();
|
||||
}
|
||||
|
||||
toggleOverlay = function () {
|
||||
openOverlay();
|
||||
makeImg(element);
|
||||
};
|
||||
|
||||
makeImg = function (el) {
|
||||
var scope = $scope;
|
||||
var dialog = dialogService.showBlockingMessage({
|
||||
title: "Saving...",
|
||||
hint: "Taking Snapshot...",
|
||||
unknownProgress: true,
|
||||
severity: "info",
|
||||
delay: true
|
||||
});
|
||||
this.$timeout(function () {
|
||||
window.EXPORT_IMAGE_TIMEOUT = 5000;
|
||||
exportImageService.exportPNGtoSRC(el).then(function (img) {
|
||||
|
||||
if (img) {
|
||||
if (dialog) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
if ($element[0].dataset.entry && $element[0].dataset.embed) {
|
||||
saveImg(img, +$element[0].dataset.entry, +$element[0].dataset.embed);
|
||||
closeOverlay(false);
|
||||
} else {
|
||||
var reader = new window.FileReader();
|
||||
reader.readAsDataURL(img);
|
||||
reader.onloadend = function () {
|
||||
//closeOverlay(true);
|
||||
$($element[0]).attr("data-snapshot", reader.result);
|
||||
$rootScope.snapshot = {'src': reader.result,
|
||||
'type': img.type,
|
||||
'size': img.size,
|
||||
'modified': Date.now()
|
||||
};
|
||||
closeOverlay(false);
|
||||
scope.$destroy();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
}, function (error) {
|
||||
if (dialog) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
closeOverlay();
|
||||
});
|
||||
}, 500);
|
||||
window.EXPORT_IMAGE_TIMEOUT = 500;
|
||||
};
|
||||
|
||||
saveImg = function (url,entryId,embedId) {
|
||||
$scope.$parent.$parent.$parent.saveSnap(url, embedId, entryId);
|
||||
};
|
||||
|
||||
if ($(document.body).find('.overlay.snapshot').length === 0) {
|
||||
toggleOverlay();
|
||||
}
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$element.off('click', toggleOverlay);
|
||||
$element.remove();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTSnapshot;
|
||||
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user