Compare commits
	
		
			96 Commits
		
	
	
		
			testathon-
			...
			notebook-i
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ab95f947e8 | ||
| 
						 | 
					179e69867b | ||
| 
						 | 
					b2fb958a77 | ||
| 
						 | 
					3ee6a04db0 | ||
| 
						 | 
					59fd3415d6 | ||
| 
						 | 
					8aeef6ae37 | ||
| 
						 | 
					0543aa9521 | ||
| 
						 | 
					78ae568302 | ||
| 
						 | 
					fad3afbd3c | ||
| 
						 | 
					6f975c2d9d | ||
| 
						 | 
					9fd397b34e | ||
| 
						 | 
					cbddfac96f | ||
| 
						 | 
					b5153b0f27 | ||
| 
						 | 
					b766a22034 | ||
| 
						 | 
					4bde1c1ab8 | ||
| 
						 | 
					1d314a91e0 | ||
| 
						 | 
					e370fbd6c5 | ||
| 
						 | 
					25cce4dd0d | ||
| 
						 | 
					78dd80d081 | ||
| 
						 | 
					944fb5e53a | ||
| 
						 | 
					ac7ea7ba44 | ||
| 
						 | 
					5d34628dd8 | ||
| 
						 | 
					c3a2ac3dd5 | ||
| 
						 | 
					62ebcd7277 | ||
| 
						 | 
					79a5e479cb | ||
| 
						 | 
					d9b66e23aa | ||
| 
						 | 
					f1c3a56147 | ||
| 
						 | 
					02e5defbdc | ||
| 
						 | 
					9897883335 | ||
| 
						 | 
					c15bb45411 | ||
| 
						 | 
					a085b2a7b8 | ||
| 
						 | 
					c1b2db848a | ||
| 
						 | 
					5d19294c11 | ||
| 
						 | 
					9b8d5f3f9c | ||
| 
						 | 
					d03f323a9b | ||
| 
						 | 
					54a453e5a0 | ||
| 
						 | 
					14894cf197 | ||
| 
						 | 
					0c6786198a | ||
| 
						 | 
					6d077b775d | ||
| 
						 | 
					144437a06e | ||
| 
						 | 
					557cd91b21 | ||
| 
						 | 
					39d3e92094 | ||
| 
						 | 
					7529a86d01 | ||
| 
						 | 
					d34e36831c | ||
| 
						 | 
					aa8fa9168a | ||
| 
						 | 
					3f1b7e0a87 | ||
| 
						 | 
					5ec3b98d1c | ||
| 
						 | 
					3366f21155 | ||
| 
						 | 
					45d5b0752b | ||
| 
						 | 
					07d7f8fd5f | ||
| 
						 | 
					2b7b4a552c | ||
| 
						 | 
					3f9bad1805 | ||
| 
						 | 
					1ad5094b72 | ||
| 
						 | 
					b54ee2257e | ||
| 
						 | 
					fcef4274e5 | ||
| 
						 | 
					744a5340d3 | ||
| 
						 | 
					d140051054 | ||
| 
						 | 
					8da74f2665 | ||
| 
						 | 
					fec1d38f7e | ||
| 
						 | 
					499655def2 | ||
| 
						 | 
					d5985b844c | ||
| 
						 | 
					59bb5d3d55 | ||
| 
						 | 
					5b298525e3 | ||
| 
						 | 
					2390278b97 | ||
| 
						 | 
					8a66731271 | ||
| 
						 | 
					0a9ea48355 | ||
| 
						 | 
					01d93306f3 | ||
| 
						 | 
					0588f9190a | ||
| 
						 | 
					1378b57567 | ||
| 
						 | 
					9e12886c66 | ||
| 
						 | 
					2d352ac574 | ||
| 
						 | 
					284dec4903 | ||
| 
						 | 
					5a0656c700 | ||
| 
						 | 
					425655bae0 | ||
| 
						 | 
					50b4d5cb28 | ||
| 
						 | 
					bc62d7d5ae | ||
| 
						 | 
					c0dcf4495e | ||
| 
						 | 
					1540fbcf54 | ||
| 
						 | 
					b15f193f5d | ||
| 
						 | 
					bdf856526b | ||
| 
						 | 
					9aafb5cbf9 | ||
| 
						 | 
					2ccf3f0fb1 | ||
| 
						 | 
					46d7c117cb | ||
| 
						 | 
					60168ea87b | ||
| 
						 | 
					5ba3afb1a8 | ||
| 
						 | 
					3974991cfd | ||
| 
						 | 
					39c5b1bbfd | ||
| 
						 | 
					c82563c80f | ||
| 
						 | 
					01fda1adfc | ||
| 
						 | 
					bf5ed84f94 | ||
| 
						 | 
					7c34f03a95 | ||
| 
						 | 
					3cf1ad8e40 | ||
| 
						 | 
					3fab80c276 | ||
| 
						 | 
					194dc43e24 | ||
| 
						 | 
					16e0eeff67 | ||
| 
						 | 
					37be478a08 | 
@@ -21,5 +21,6 @@
 | 
			
		||||
    "shadow": "outer",
 | 
			
		||||
    "strict": "implied",
 | 
			
		||||
    "undef": true,
 | 
			
		||||
    "unused": "vars"
 | 
			
		||||
    "unused": "vars",
 | 
			
		||||
    "latedef": "nofunc"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,7 @@ and [`gulp`](http://gulpjs.com/).
 | 
			
		||||
 | 
			
		||||
To build Open MCT for deployment:
 | 
			
		||||
 | 
			
		||||
`npm run prepublish`
 | 
			
		||||
`npm run prepare`
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
@@ -25,4 +25,4 @@
 | 
			
		||||
    "html2canvas": "^0.4.1",
 | 
			
		||||
    "moment-timezone": "^0.5.13"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								circle.yml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								circle.yml
									
									
									
									
									
								
							@@ -1,3 +1,11 @@
 | 
			
		||||
machine:
 | 
			
		||||
  node:
 | 
			
		||||
    version: 4.7.0
 | 
			
		||||
 | 
			
		||||
dependencies:
 | 
			
		||||
  pre:
 | 
			
		||||
    - npm install -g npm@latest
 | 
			
		||||
 | 
			
		||||
deployment:
 | 
			
		||||
  production:
 | 
			
		||||
    branch: master
 | 
			
		||||
@@ -16,4 +24,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 prepublish`
 | 
			
		||||
`npm run prepare`
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,7 @@ define([
 | 
			
		||||
        amplitude: 1,
 | 
			
		||||
        period: 10,
 | 
			
		||||
        offset: 0,
 | 
			
		||||
        dataRateInHz: 1,
 | 
			
		||||
        phase: 0
 | 
			
		||||
        dataRateInHz: 1
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function GeneratorProvider() {
 | 
			
		||||
@@ -51,12 +50,9 @@ define([
 | 
			
		||||
            'amplitude',
 | 
			
		||||
            'period',
 | 
			
		||||
            'offset',
 | 
			
		||||
            'dataRateInHz',
 | 
			
		||||
            'phase',
 | 
			
		||||
            'dataRateInHz'
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        request = request || {};
 | 
			
		||||
 | 
			
		||||
        var workerRequest = {};
 | 
			
		||||
 | 
			
		||||
        props.forEach(function (prop) {
 | 
			
		||||
@@ -71,7 +67,7 @@ define([
 | 
			
		||||
            }
 | 
			
		||||
            workerRequest[prop] = Number(workerRequest[prop]);
 | 
			
		||||
        });
 | 
			
		||||
        workerRequest.name = domainObject.name;
 | 
			
		||||
 | 
			
		||||
        return workerRequest;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,80 +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 StateGeneratorProvider() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function pointForTimestamp(timestamp, duration, name) {
 | 
			
		||||
        return {
 | 
			
		||||
            name: name,
 | 
			
		||||
            utc: Math.floor(timestamp / duration) * duration,
 | 
			
		||||
            value: Math.floor(timestamp / duration) % 2
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.supportsSubscribe = function (domainObject) {
 | 
			
		||||
        return domainObject.type === 'example.state-generator';
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.subscribe = function (domainObject, callback) {
 | 
			
		||||
        var duration = domainObject.telemetry.duration * 1000;
 | 
			
		||||
 | 
			
		||||
        var interval = setInterval(function () {
 | 
			
		||||
            var now = Date.now();
 | 
			
		||||
            callback(pointForTimestamp(now, duration, domainObject.name));
 | 
			
		||||
        }, duration);
 | 
			
		||||
 | 
			
		||||
        return function () {
 | 
			
		||||
            clearInterval(interval);
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.supportsRequest = function (domainObject, options) {
 | 
			
		||||
        return domainObject.type === 'example.state-generator';
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.request = function (domainObject, options) {
 | 
			
		||||
        var start = options.start;
 | 
			
		||||
        var end = options.end;
 | 
			
		||||
        var duration = domainObject.telemetry.duration * 1000;
 | 
			
		||||
        if (options.strategy === 'latest' || options.size === 1) {
 | 
			
		||||
            start = end;
 | 
			
		||||
        }
 | 
			
		||||
        var data = [];
 | 
			
		||||
        while (start <= end && data.length < 5000) {
 | 
			
		||||
            data.push(pointForTimestamp(start, duration, domainObject.name));
 | 
			
		||||
            start += 5000;
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve(data);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return StateGeneratorProvider;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
@@ -62,11 +62,10 @@
 | 
			
		||||
                self.postMessage({
 | 
			
		||||
                    id: message.id,
 | 
			
		||||
                    data: {
 | 
			
		||||
                        name: data.name,
 | 
			
		||||
                        utc: nextStep,
 | 
			
		||||
                        yesterday: nextStep - 60*60*24*1000,
 | 
			
		||||
                        sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase),
 | 
			
		||||
                        cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase)
 | 
			
		||||
                        sin: sin(nextStep, data.period, data.amplitude, data.offset),
 | 
			
		||||
                        cos: cos(nextStep, data.period, data.amplitude, data.offset)
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                nextStep += step;
 | 
			
		||||
@@ -83,22 +82,21 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onRequest(message) {
 | 
			
		||||
        var request = message.data;
 | 
			
		||||
        if (request.end == undefined) {
 | 
			
		||||
            request.end = Date.now();
 | 
			
		||||
        var data = message.data;
 | 
			
		||||
        if (data.end == undefined) {
 | 
			
		||||
            data.end = Date.now();
 | 
			
		||||
        }
 | 
			
		||||
        if (request.start == undefined){
 | 
			
		||||
            request.start = request.end - FIFTEEN_MINUTES;
 | 
			
		||||
        if (data.start == undefined){
 | 
			
		||||
            data.start = data.end - FIFTEEN_MINUTES;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var now = Date.now();
 | 
			
		||||
        var start = request.start;
 | 
			
		||||
        var end = request.end > now ? now : request.end;
 | 
			
		||||
        var amplitude = request.amplitude;
 | 
			
		||||
        var period = request.period;
 | 
			
		||||
        var offset = request.offset;
 | 
			
		||||
        var dataRateInHz = request.dataRateInHz;
 | 
			
		||||
        var phase = request.phase;
 | 
			
		||||
        var start = data.start;
 | 
			
		||||
        var end = data.end > now ? now : data.end;
 | 
			
		||||
        var amplitude = data.amplitude;
 | 
			
		||||
        var period = data.period;
 | 
			
		||||
        var offset = data.offset;
 | 
			
		||||
        var dataRateInHz = data.dataRateInHz;
 | 
			
		||||
 | 
			
		||||
        var step = 1000 / dataRateInHz;
 | 
			
		||||
        var nextStep = start - (start % step) + step;
 | 
			
		||||
@@ -107,11 +105,10 @@
 | 
			
		||||
 | 
			
		||||
        for (; nextStep < end && data.length < 5000; nextStep += step) {
 | 
			
		||||
            data.push({
 | 
			
		||||
                name: request.name,
 | 
			
		||||
                utc: nextStep,
 | 
			
		||||
                yesterday: nextStep - 60*60*24*1000,
 | 
			
		||||
                sin: sin(nextStep, period, amplitude, offset, phase),
 | 
			
		||||
                cos: cos(nextStep, period, amplitude, offset, phase)
 | 
			
		||||
                sin: sin(nextStep, period, amplitude, offset),
 | 
			
		||||
                cos: cos(nextStep, period, amplitude, offset)
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        self.postMessage({
 | 
			
		||||
@@ -120,14 +117,14 @@
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function cos(timestamp, period, amplitude, offset, phase) {
 | 
			
		||||
    function cos(timestamp, period, amplitude, offset) {
 | 
			
		||||
        return amplitude *
 | 
			
		||||
            Math.cos(phase + (timestamp / period / 1000 * Math.PI * 2)) + offset;
 | 
			
		||||
            Math.cos(timestamp / period / 1000 * Math.PI * 2) + offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sin(timestamp, period, amplitude, offset, phase) {
 | 
			
		||||
    function sin(timestamp, period, amplitude, offset) {
 | 
			
		||||
        return amplitude *
 | 
			
		||||
            Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + offset;
 | 
			
		||||
            Math.sin(timestamp / period / 1000 * Math.PI * 2) + offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sendError(error, message) {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,10 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    "./GeneratorProvider",
 | 
			
		||||
    "./SinewaveLimitCapability",
 | 
			
		||||
    "./StateGeneratorProvider"
 | 
			
		||||
    "./SinewaveLimitCapability"
 | 
			
		||||
], function (
 | 
			
		||||
    GeneratorProvider,
 | 
			
		||||
    SinewaveLimitCapability,
 | 
			
		||||
    StateGeneratorProvider
 | 
			
		||||
    SinewaveLimitCapability
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    var legacyExtensions = {
 | 
			
		||||
@@ -48,75 +46,6 @@ define([
 | 
			
		||||
                openmct.legacyExtension(type, extension)
 | 
			
		||||
            })
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.types.addType("example.state-generator", {
 | 
			
		||||
            name: "State Generator",
 | 
			
		||||
            description: "For development use.  Generates test enumerated telemetry by cycling through a given set of states",
 | 
			
		||||
            cssClass: "icon-telemetry",
 | 
			
		||||
            creatable: true,
 | 
			
		||||
            form: [
 | 
			
		||||
                {
 | 
			
		||||
                    name: "State Duration (seconds)",
 | 
			
		||||
                    control: "textfield",
 | 
			
		||||
                    cssClass: "l-input-sm l-numeric",
 | 
			
		||||
                    key: "duration",
 | 
			
		||||
                    required: true,
 | 
			
		||||
                    property: [
 | 
			
		||||
                        "telemetry",
 | 
			
		||||
                        "duration"
 | 
			
		||||
                    ],
 | 
			
		||||
                    pattern: "^\\d*(\\.\\d*)?$"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            initialize: function (object) {
 | 
			
		||||
                object.telemetry = {
 | 
			
		||||
                    duration: 5,
 | 
			
		||||
                    values: [
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "name",
 | 
			
		||||
                            name: "Name"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "utc",
 | 
			
		||||
                            name: "Time",
 | 
			
		||||
                            format: "utc",
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                domain: 1
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "state",
 | 
			
		||||
                            source: "value",
 | 
			
		||||
                            name: "State",
 | 
			
		||||
                            format: "enum",
 | 
			
		||||
                            enumerations: [
 | 
			
		||||
                                {
 | 
			
		||||
                                    value: 0,
 | 
			
		||||
                                    string: "OFF"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    value: 1,
 | 
			
		||||
                                    string: "ON"
 | 
			
		||||
                                }
 | 
			
		||||
                            ],
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                range: 1
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "value",
 | 
			
		||||
                            name: "Value",
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                range: 2
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.telemetry.addProvider(new StateGeneratorProvider());
 | 
			
		||||
 | 
			
		||||
        openmct.types.addType("generator", {
 | 
			
		||||
            name: "Sine Wave Generator",
 | 
			
		||||
            description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
 | 
			
		||||
@@ -170,18 +99,6 @@ define([
 | 
			
		||||
                        "dataRateInHz"
 | 
			
		||||
                    ],
 | 
			
		||||
                    pattern: "^\\d*(\\.\\d*)?$"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: "Phase (radians)",
 | 
			
		||||
                    control: "textfield",
 | 
			
		||||
                    cssClass: "l-input-sm l-numeric",
 | 
			
		||||
                    key: "phase",
 | 
			
		||||
                    required: true,
 | 
			
		||||
                    property: [
 | 
			
		||||
                        "telemetry",
 | 
			
		||||
                        "phase"
 | 
			
		||||
                    ],
 | 
			
		||||
                    pattern: "^\\d*(\\.\\d*)?$"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            initialize: function (object) {
 | 
			
		||||
@@ -190,12 +107,7 @@ define([
 | 
			
		||||
                    amplitude: 1,
 | 
			
		||||
                    offset: 0,
 | 
			
		||||
                    dataRateInHz: 1,
 | 
			
		||||
                    phase: 0,
 | 
			
		||||
                    values: [
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "name",
 | 
			
		||||
                            name: "Name"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "utc",
 | 
			
		||||
                            name: "Time",
 | 
			
		||||
@@ -230,7 +142,6 @@ define([
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.telemetry.addProvider(new GeneratorProvider());
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,9 +48,8 @@ define([
 | 
			
		||||
                "https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
        function pointForTimestamp(timestamp, name) {
 | 
			
		||||
        function pointForTimestamp(timestamp) {
 | 
			
		||||
            return {
 | 
			
		||||
                name: name,
 | 
			
		||||
                utc: Math.floor(timestamp / 5000) * 5000,
 | 
			
		||||
                url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length]
 | 
			
		||||
            };
 | 
			
		||||
@@ -62,7 +61,7 @@ define([
 | 
			
		||||
            },
 | 
			
		||||
            subscribe: function (domainObject, callback) {
 | 
			
		||||
                var interval = setInterval(function () {
 | 
			
		||||
                    callback(pointForTimestamp(Date.now(), domainObject.name));
 | 
			
		||||
                    callback(pointForTimestamp(Date.now()));
 | 
			
		||||
                }, 5000);
 | 
			
		||||
 | 
			
		||||
                return function (interval) {
 | 
			
		||||
@@ -80,8 +79,8 @@ define([
 | 
			
		||||
                var start = options.start;
 | 
			
		||||
                var end = options.end;
 | 
			
		||||
                var data = [];
 | 
			
		||||
                while (start <= end && data.length < 5000) {
 | 
			
		||||
                    data.push(pointForTimestamp(start, domainObject.name));
 | 
			
		||||
                while (start < end && data.length < 5000) {
 | 
			
		||||
                    data.push(pointForTimestamp(start));
 | 
			
		||||
                    start += 5000;
 | 
			
		||||
                }
 | 
			
		||||
                return Promise.resolve(data);
 | 
			
		||||
@@ -94,7 +93,7 @@ define([
 | 
			
		||||
                    options.strategy === 'latest';
 | 
			
		||||
            },
 | 
			
		||||
            request: function (domainObject, options) {
 | 
			
		||||
                return Promise.resolve([pointForTimestamp(Date.now(), domainObject.name)]);
 | 
			
		||||
                return Promise.resolve([pointForTimestamp(Date.now())]);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -110,10 +109,6 @@ define([
 | 
			
		||||
                initialize: function (object) {
 | 
			
		||||
                    object.telemetry = {
 | 
			
		||||
                        values: [
 | 
			
		||||
                            {
 | 
			
		||||
                                name: 'Name',
 | 
			
		||||
                                key: 'name'
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: 'Time',
 | 
			
		||||
                                key: 'utc',
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,8 @@
 | 
			
		||||
 | 
			
		||||
/*global require,__dirname*/
 | 
			
		||||
 | 
			
		||||
require("v8-compile-cache");
 | 
			
		||||
 | 
			
		||||
var gulp = require('gulp'),
 | 
			
		||||
    sourcemaps = require('gulp-sourcemaps'),
 | 
			
		||||
    path = require('path'),
 | 
			
		||||
@@ -177,4 +179,4 @@ gulp.task('install', [ 'assets', 'scripts' ]);
 | 
			
		||||
 | 
			
		||||
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
 | 
			
		||||
 | 
			
		||||
gulp.task('build', [ 'verify', 'install' ]);
 | 
			
		||||
gulp.task('build', [ 'verify', 'install' ]);
 | 
			
		||||
@@ -43,6 +43,9 @@
 | 
			
		||||
            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.Conductor({
 | 
			
		||||
                menuOptions: [
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,8 @@ 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},
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@ requirejs.config({
 | 
			
		||||
        "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",
 | 
			
		||||
@@ -48,7 +49,8 @@ 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"
 | 
			
		||||
        "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
 | 
			
		||||
        "painterro": "node_modules/@cristian77/painterro/build/painterro.min"
 | 
			
		||||
    },
 | 
			
		||||
    "shim": {
 | 
			
		||||
        "angular": {
 | 
			
		||||
@@ -66,6 +68,9 @@ requirejs.config({
 | 
			
		||||
        "moment-duration-format": {
 | 
			
		||||
            "deps": ["moment"]
 | 
			
		||||
        },
 | 
			
		||||
        "painterro": {
 | 
			
		||||
            "exports": "Painterro"
 | 
			
		||||
        },
 | 
			
		||||
        "saveAs": {
 | 
			
		||||
            "exports": "saveAs"
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
  "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",
 | 
			
		||||
@@ -15,7 +16,8 @@
 | 
			
		||||
    "d3-time-format": "^2.0.3",
 | 
			
		||||
    "express": "^4.13.1",
 | 
			
		||||
    "minimist": "^1.1.1",
 | 
			
		||||
    "request": "^2.69.0"
 | 
			
		||||
    "request": "^2.69.0",
 | 
			
		||||
    "vue": "^2.5.6"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "bower": "^1.7.7",
 | 
			
		||||
@@ -49,7 +51,8 @@
 | 
			
		||||
    "moment": "^2.11.1",
 | 
			
		||||
    "node-bourbon": "^4.2.3",
 | 
			
		||||
    "requirejs": "2.1.x",
 | 
			
		||||
    "split": "^1.0.0"
 | 
			
		||||
    "split": "^1.0.0",
 | 
			
		||||
    "v8-compile-cache": "^1.1.0"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "start": "node app.js",
 | 
			
		||||
@@ -59,7 +62,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",
 | 
			
		||||
    "prepublish": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
 | 
			
		||||
    "prepare": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
 
 | 
			
		||||
@@ -28,16 +28,6 @@ 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 &&
 | 
			
		||||
@@ -59,10 +49,7 @@ define(
 | 
			
		||||
 | 
			
		||||
            var removeCheck = navigationService
 | 
			
		||||
                .checkBeforeNavigation(function () {
 | 
			
		||||
                    if (isDirty(domainObject)) {
 | 
			
		||||
                        return "Continuing will cause the loss of any unsaved changes.";
 | 
			
		||||
                    }
 | 
			
		||||
                    return false;
 | 
			
		||||
                    return "Continuing will cause the loss of any unsaved changes.";
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            $scope.$on('$destroy', function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,8 @@ define(
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var selectedObjectComposition = selection[0].context.oldItem.useCapability('composition');
 | 
			
		||||
            var selected = selection[0].context.oldItem;
 | 
			
		||||
            var selectedObjectComposition = selected && selected.useCapability('composition');
 | 
			
		||||
 | 
			
		||||
            if (selectedObjectComposition) {
 | 
			
		||||
                selectedObjectComposition.then(function (composition) {
 | 
			
		||||
 
 | 
			
		||||
@@ -44,11 +44,17 @@ define(
 | 
			
		||||
            this.selectedObj = undefined;
 | 
			
		||||
 | 
			
		||||
            openmct.selection.on('change', function (selection) {
 | 
			
		||||
                if (selection[0] && selection[0].context.toolbar) {
 | 
			
		||||
                    this.select(selection[0].context.toolbar);
 | 
			
		||||
                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));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -104,10 +104,10 @@ define(
 | 
			
		||||
                mockEditorCapability.isEditContextRoot.andReturn(false);
 | 
			
		||||
                mockEditorCapability.dirty.andReturn(false);
 | 
			
		||||
 | 
			
		||||
                expect(checkFn()).toBe(false);
 | 
			
		||||
                expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
 | 
			
		||||
 | 
			
		||||
                mockEditorCapability.isEditContextRoot.andReturn(true);
 | 
			
		||||
                expect(checkFn()).toBe(false);
 | 
			
		||||
                expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
 | 
			
		||||
 | 
			
		||||
                mockEditorCapability.dirty.andReturn(true);
 | 
			
		||||
                expect(checkFn())
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ $plotXBarH: 32px;
 | 
			
		||||
$plotLegendH: 20px;
 | 
			
		||||
$plotSwatchD: 8px;
 | 
			
		||||
// 1: Top, 2: right, 3: bottom, 4: left
 | 
			
		||||
$plotDisplayArea: (0, 0, $plotXBarH, $plotYBarW);
 | 
			
		||||
$plotDisplayArea: ($plotLegendH + $interiorMargin, 0, $plotXBarH, $plotYBarW);
 | 
			
		||||
/* min plot height is based on user testing to find minimum useful height */
 | 
			
		||||
$plotMinH: 95px;
 | 
			
		||||
/*************** Bubbles */
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@
 | 
			
		||||
    * Use https://icomoon.io/app with icomoon-project-openmct-symbols-12px.json
 | 
			
		||||
    * to generate font files
 | 
			
		||||
    */
 | 
			
		||||
    font-family: 'symbolsfont-12px';
 | 
			
		||||
    font-family: 'symbolsfont 12px';
 | 
			
		||||
    src: url($dirCommonRes + 'fonts/symbols/openmct-symbols-12px.eot');
 | 
			
		||||
    src: url($dirCommonRes + 'fonts/symbols/openmct-symbols-12px.eot?#iefix') format('embedded-opentype'),
 | 
			
		||||
    url($dirCommonRes + 'fonts/symbols/openmct-symbols-12px.woff') format('woff'),
 | 
			
		||||
@@ -248,12 +248,6 @@ a.disabled {
 | 
			
		||||
    color: rgba(#fff, 0.2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comma-list span {
 | 
			
		||||
    &:not(:first-child) {
 | 
			
		||||
        &:before { content: ', '; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.test-stripes {
 | 
			
		||||
    @include bgDiagonalStripes();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -44,12 +44,6 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.t-alert-unsynced {
 | 
			
		||||
    @extend .icon-alert-triangle;
 | 
			
		||||
    color: $colorPausedBg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar .ui-symbol {
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
@@ -87,5 +81,18 @@
 | 
			
		||||
            @include transform(scale(0.3));
 | 
			
		||||
            z-index: 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
/*        .t-item-icon-glyph {
 | 
			
		||||
            &:after {
 | 
			
		||||
                color: $colorIconLink;
 | 
			
		||||
                content: '\e921'; //$glyph-icon-link;
 | 
			
		||||
                height: auto; width: auto;
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                left: 0; top: 0; right: 0; bottom: 20%;
 | 
			
		||||
                @include transform-origin(bottom left);
 | 
			
		||||
                @include transform(scale(0.3));
 | 
			
		||||
                z-index: 2;
 | 
			
		||||
            }
 | 
			
		||||
        }*/
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,6 @@
 | 
			
		||||
    .l-inspector-part {
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding-right: $interiorMargin;
 | 
			
		||||
 | 
			
		||||
        .tree .form {
 | 
			
		||||
            margin-left: $treeVCW + $interiorMarginLg;
 | 
			
		||||
        }
 | 
			
		||||
@@ -79,7 +78,6 @@
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .form-row {
 | 
			
		||||
                // To be replaced with .inspector-config, see below.
 | 
			
		||||
                @include align-items(center);
 | 
			
		||||
                border: none !important;
 | 
			
		||||
                margin-bottom: 0 !important;
 | 
			
		||||
@@ -101,12 +99,15 @@
 | 
			
		||||
        position: relative;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ul li {
 | 
			
		||||
        margin-bottom: $interiorMarginLg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    em.t-inspector-part-header {
 | 
			
		||||
        border-radius: $basicCr;
 | 
			
		||||
        background-color: $colorInspectorSectionHeaderBg;
 | 
			
		||||
        color: $colorInspectorSectionHeaderFg;
 | 
			
		||||
        margin-top: $interiorMarginLg;
 | 
			
		||||
        //margin-bottom: $interiorMargin;
 | 
			
		||||
        margin-bottom: $interiorMargin;
 | 
			
		||||
        padding: floor($formTBPad * .75) $formLRPad;
 | 
			
		||||
        text-transform: uppercase;
 | 
			
		||||
    }
 | 
			
		||||
@@ -200,102 +201,3 @@ mct-representation:not(.s-status-editing) .l-inspect {
 | 
			
		||||
        pointer-events: inherit;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NEW COMPACT FORM, FOR USE IN INSPECTOR
 | 
			
		||||
// ul > li > label, control
 | 
			
		||||
// Make a new UL for each form section
 | 
			
		||||
// Allow control-first, controls-below
 | 
			
		||||
 | 
			
		||||
.l-inspect .tree ul li,
 | 
			
		||||
.inspector-config ul li {
 | 
			
		||||
    padding: 2px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.inspector-config {
 | 
			
		||||
    $labelW: 40%;
 | 
			
		||||
    $minW: $labelW;
 | 
			
		||||
    ul {
 | 
			
		||||
        margin-bottom: $interiorMarginLg;
 | 
			
		||||
        li {
 | 
			
		||||
            @include display(flex);
 | 
			
		||||
            @include flex-wrap(wrap);
 | 
			
		||||
            @include align-items(center);
 | 
			
		||||
            label,
 | 
			
		||||
            .control {
 | 
			
		||||
                @include display(flex);
 | 
			
		||||
                min-width: $minW;
 | 
			
		||||
            }
 | 
			
		||||
            label {
 | 
			
		||||
                line-height: inherit;
 | 
			
		||||
                padding: $interiorMarginSm 0;
 | 
			
		||||
                width: $labelW;
 | 
			
		||||
            }
 | 
			
		||||
            .control {
 | 
			
		||||
                @include flex-grow(1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:not(.section-header) {
 | 
			
		||||
                &:not(.connects-to-previous) {
 | 
			
		||||
                    //border-top: 1px solid $colorFormLines;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.connects-to-previous {
 | 
			
		||||
                padding-top: 0 !important;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.section-header {
 | 
			
		||||
                margin-top: $interiorMarginLg;
 | 
			
		||||
                border-top: 1px solid $colorFormLines;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.controls-first {
 | 
			
		||||
                .control {
 | 
			
		||||
                    @include flex-grow(0);
 | 
			
		||||
                    margin-right: $interiorMargin;
 | 
			
		||||
                    min-width: 0;
 | 
			
		||||
                    order: 1;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
                label {
 | 
			
		||||
                    @include flex-grow(1);
 | 
			
		||||
                    order: 2;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            &.controls-under {
 | 
			
		||||
                display: block;
 | 
			
		||||
                .control, label {
 | 
			
		||||
                    display: block;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ul li {
 | 
			
		||||
                    border-top: none !important;
 | 
			
		||||
                    padding: 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .form-error {
 | 
			
		||||
        // Block element that visually flags an error and contains a message
 | 
			
		||||
        background-color: $colorFormFieldErrorBg;
 | 
			
		||||
        color: $colorFormFieldErrorFg;
 | 
			
		||||
        border-radius: $basicCr;
 | 
			
		||||
        display: block;
 | 
			
		||||
        padding: 1px 6px;
 | 
			
		||||
        &:before {
 | 
			
		||||
            content: $glyph-icon-alert-triangle;
 | 
			
		||||
            display: inline;
 | 
			
		||||
            font-family: symbolsfont;
 | 
			
		||||
            margin-right: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tree .inspector-config {
 | 
			
		||||
    margin-left: $treeVCW + $interiorMarginLg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,6 @@
 | 
			
		||||
@import "fixed-position";
 | 
			
		||||
@import "lists/tabular";
 | 
			
		||||
@import "plots/plots-main";
 | 
			
		||||
@import "plots/legend";
 | 
			
		||||
@import "iframe";
 | 
			
		||||
@import "views";
 | 
			
		||||
@import "items/item";
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-view-section {
 | 
			
		||||
    //@include test(orange, 0.1);
 | 
			
		||||
	@include absPosDefault(0);
 | 
			
		||||
	h2 {
 | 
			
		||||
		color: #fff;
 | 
			
		||||
 
 | 
			
		||||
@@ -150,26 +150,6 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** VIEW CONTROLS */
 | 
			
		||||
// Expand/collapse > and v arrows, used in tree and plot legend
 | 
			
		||||
// Moved this over from a tree-only context 5/18/17
 | 
			
		||||
 | 
			
		||||
.view-control {
 | 
			
		||||
    @extend .ui-symbol;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    height: 1em; width: 1em;
 | 
			
		||||
    line-height: inherit;
 | 
			
		||||
    &:before {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        @include trans-prop-nice(transform, 100ms);
 | 
			
		||||
        content: $glyph-icon-arrow-right;
 | 
			
		||||
        @include transform-origin(center);
 | 
			
		||||
    }
 | 
			
		||||
    &.expanded:before {
 | 
			
		||||
        @include transform(rotate(90deg));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** CUSTOM CHECKBOXES */
 | 
			
		||||
label.checkbox.custom,
 | 
			
		||||
label.radio.custom {
 | 
			
		||||
 
 | 
			
		||||
@@ -398,6 +398,10 @@ body.desktop .t-message-list {
 | 
			
		||||
    .object-header {
 | 
			
		||||
        .t-object-alert {
 | 
			
		||||
            display: inline;
 | 
			
		||||
            &.t-alert-unsynced {
 | 
			
		||||
                @extend .icon-alert-triangle;
 | 
			
		||||
                color: $colorPausedBg;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -69,5 +69,4 @@
 | 
			
		||||
			margin-left: $interiorMargin;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -34,7 +34,18 @@ body.touch {
 | 
			
		||||
		line-height: $mobileTreeItemH !important;
 | 
			
		||||
		.view-control {
 | 
			
		||||
            font-size: 1em;
 | 
			
		||||
            width: ceil($mobileTreeItemH * 0.5);
 | 
			
		||||
            margin-right: $interiorMargin;
 | 
			
		||||
            width: ceil($mobileTreeItemH * 0.75);
 | 
			
		||||
            &.has-children {
 | 
			
		||||
                &:before {
 | 
			
		||||
                    content: $glyph-icon-arrow-down;
 | 
			
		||||
                    left: 50%;
 | 
			
		||||
                    @include transform(translateX(-50%) rotate(-90deg));
 | 
			
		||||
                }
 | 
			
		||||
                &.expanded:before {
 | 
			
		||||
                    @include transform(translateX(-50%) rotate(0deg));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
		.t-object-label {
 | 
			
		||||
			line-height: inherit;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,208 +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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.gl-plot {
 | 
			
		||||
    .gl-plot-legend {
 | 
			
		||||
        min-height: $plotLegendH;
 | 
			
		||||
 | 
			
		||||
        .view-control {
 | 
			
		||||
            font-size: 1em;
 | 
			
		||||
            margin-right: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        table {
 | 
			
		||||
            table-layout: fixed;
 | 
			
		||||
            tr {
 | 
			
		||||
                display: table-row;
 | 
			
		||||
            }
 | 
			
		||||
            th,
 | 
			
		||||
            td {
 | 
			
		||||
                @include ellipsize(); // Note: this won't work if table-layout uses anything other than fixed.
 | 
			
		||||
                display: table-cell;
 | 
			
		||||
                padding: 1px 3px; // Tighter than standard tabular padding
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.hover-on-plot {
 | 
			
		||||
            // User is hovering over the plot to get a value at a point
 | 
			
		||||
            .hover-value-enabled {
 | 
			
		||||
                background-color: $legendHoverValueBg;
 | 
			
		||||
                border-radius: $smallCr;
 | 
			
		||||
                padding: 0 $interiorMarginSm;
 | 
			
		||||
                &:before {
 | 
			
		||||
                    opacity: 0.5;
 | 
			
		||||
                }
 | 
			
		||||
                &.cursor-hover,
 | 
			
		||||
                .value-to-display-nearestTimestamp,
 | 
			
		||||
                .value-to-display-nearestValue
 | 
			
		||||
                {
 | 
			
		||||
                    @extend .icon-crosshair-12px;
 | 
			
		||||
                    &:before {
 | 
			
		||||
                        font-size: 9px;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                &.value-to-display-min:before {
 | 
			
		||||
                    content: 'MIN ';
 | 
			
		||||
                }
 | 
			
		||||
                &.value-to-display-max:before {
 | 
			
		||||
                    content: 'MAX ';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; }
 | 
			
		||||
    &.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; }
 | 
			
		||||
 | 
			
		||||
    /***************** GENERAL STYLES, ALL STATES */
 | 
			
		||||
    .plot-legend-item {
 | 
			
		||||
        // General styles for legend items, both expanded and collapsed legend states
 | 
			
		||||
        .plot-series-color-swatch {
 | 
			
		||||
            border-radius: $smallCr;
 | 
			
		||||
            border: 1px solid $colorBodyBg;
 | 
			
		||||
            display: inline-block;
 | 
			
		||||
            height: $plotSwatchD;
 | 
			
		||||
            width: $plotSwatchD;
 | 
			
		||||
        }
 | 
			
		||||
        .plot-series-name {
 | 
			
		||||
            display: inline;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .plot-series-value {
 | 
			
		||||
            @include ellipsize();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** GENERAL STYLES, COLLAPSED */
 | 
			
		||||
    &.plot-legend-collapsed {
 | 
			
		||||
        // .plot-legend-item is a span of spans.
 | 
			
		||||
        &.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; }
 | 
			
		||||
        &.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; }
 | 
			
		||||
        &.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; }
 | 
			
		||||
        &.plot-legend-left .gl-plot-legend { margin-right: $interiorMargin; }
 | 
			
		||||
 | 
			
		||||
        .plot-legend-item {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            &:not(:first-child) {
 | 
			
		||||
                margin-left: $interiorMarginLg;
 | 
			
		||||
            }
 | 
			
		||||
            .plot-series-swatch-and-name,
 | 
			
		||||
            .plot-series-value {
 | 
			
		||||
                @include ellipsize();
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .plot-series-swatch-and-name {
 | 
			
		||||
                margin-right: $interiorMarginSm;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .plot-series-value {
 | 
			
		||||
                text-align: left;
 | 
			
		||||
                width: 170px;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** GENERAL STYLES, EXPANDED */
 | 
			
		||||
    &.plot-legend-expanded {
 | 
			
		||||
        .gl-plot-legend {
 | 
			
		||||
            max-height: 70%;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .plot-wrapper-expanded-legend {
 | 
			
		||||
            overflow-y: auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.plot-legend-top .gl-plot-legend {
 | 
			
		||||
            margin-bottom: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
        &.plot-legend-bottom .gl-plot-legend {
 | 
			
		||||
            margin-top: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** TOP OR BOTTOM */
 | 
			
		||||
    &.plot-legend-top,
 | 
			
		||||
    &.plot-legend-bottom {
 | 
			
		||||
        // General styles when legend is on the top or bottom
 | 
			
		||||
        @extend .l-flex-col;
 | 
			
		||||
        &.plot-legend-collapsed {
 | 
			
		||||
            // COLLAPSED ON TOP OR BOTTOM
 | 
			
		||||
            .plot-wrapper-collapsed-legend {
 | 
			
		||||
                display: flex;
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
                overflow: hidden;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** EITHER SIDE */
 | 
			
		||||
    &.plot-legend-left,
 | 
			
		||||
    &.plot-legend-right {
 | 
			
		||||
        @extend .l-flex-row;
 | 
			
		||||
        // If the legend is expanded, use flex-col instead so that the legend gets the width it needs.
 | 
			
		||||
        &.plot-legend-expanded {
 | 
			
		||||
            // EXPANDED, ON EITHER SIDE
 | 
			
		||||
            @extend .l-flex-col;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.plot-legend-collapsed {
 | 
			
		||||
            // COLLAPSED, ON EITHER SIDE
 | 
			
		||||
            .gl-plot-legend {
 | 
			
		||||
                max-height: inherit;
 | 
			
		||||
                width: 25%;
 | 
			
		||||
            }
 | 
			
		||||
            .plot-wrapper-collapsed-legend {
 | 
			
		||||
                display: flex;
 | 
			
		||||
                flex-flow: column nowrap;
 | 
			
		||||
                min-width: 0;
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
                overflow-y: auto;
 | 
			
		||||
            }
 | 
			
		||||
            .plot-legend-item {
 | 
			
		||||
                margin-bottom: 1px;
 | 
			
		||||
                margin-left: 0;
 | 
			
		||||
                flex-wrap: wrap;
 | 
			
		||||
                .plot-series-swatch-and-name {
 | 
			
		||||
                    flex: 0 1 auto;
 | 
			
		||||
                    min-width: 20%;
 | 
			
		||||
                }
 | 
			
		||||
                .plot-series-value {
 | 
			
		||||
                    flex: 0 1 auto;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** ON BOTTOM OR RIGHT */
 | 
			
		||||
    &.plot-legend-right:not(.plot-legend-expanded),
 | 
			
		||||
    &.plot-legend-bottom {
 | 
			
		||||
        .gl-plot-legend {
 | 
			
		||||
            order: 2;
 | 
			
		||||
        }
 | 
			
		||||
        .plot-wrapper-axis-and-display-area {
 | 
			
		||||
            order: 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,42 +20,10 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.abs.holder-plot {
 | 
			
		||||
    right: $interiorMargin; // Fend off the scrollbar when less than min-height;
 | 
			
		||||
    .t-object-alert.t-alert-unsynced {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
    // Fend off the scrollbar when less than min-height;
 | 
			
		||||
    right: $interiorMargin;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/********************************************* STACKED PLOT LAYOUT */
 | 
			
		||||
.t-plot-stacked {
 | 
			
		||||
    .l-view-section {
 | 
			
		||||
        //  Make this a flex container
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-flow: column nowrap;
 | 
			
		||||
        .gl-plot.child-frame {
 | 
			
		||||
            mct-plot { 
 | 
			
		||||
                display: flex; 
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
                height: 100%;
 | 
			
		||||
                position: relative;
 | 
			
		||||
            }
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            &:not(:first-child) {
 | 
			
		||||
                margin-top: $interiorMargin;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .s-status-timeconductor-unsynced .holder-plot {
 | 
			
		||||
        .t-object-alert.t-alert-unsynced {
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.gl-plot {
 | 
			
		||||
	color: $colorPlotFg;
 | 
			
		||||
	font-size: 0.7rem;
 | 
			
		||||
@@ -64,19 +32,6 @@
 | 
			
		||||
	height: 100%;
 | 
			
		||||
    min-height: $plotMinH;
 | 
			
		||||
 | 
			
		||||
    /********************************************* AXIS AND DISPLAY AREA */
 | 
			
		||||
    .plot-wrapper-axis-and-display-area {
 | 
			
		||||
        margin-top: $interiorMargin; // Keep the top tick label from getting clipped
 | 
			
		||||
        position: relative;
 | 
			
		||||
        flex: 1 1 auto;
 | 
			
		||||
        .t-object-alert {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            display: block;
 | 
			
		||||
            font-size: 1.5em;
 | 
			
		||||
            top: $interiorMarginSm; left: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .gl-plot-wrapper-display-area-and-x-axis {
 | 
			
		||||
        // Holds the plot area and the X-axis only
 | 
			
		||||
        position: absolute;
 | 
			
		||||
@@ -94,6 +49,7 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .gl-plot-axis-area.gl-plot-x {
 | 
			
		||||
            //@include test(green);
 | 
			
		||||
            top: auto;
 | 
			
		||||
            right: 0;
 | 
			
		||||
            bottom: 0;
 | 
			
		||||
@@ -107,7 +63,7 @@
 | 
			
		||||
	.gl-plot-axis-area {
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		&.gl-plot-y {
 | 
			
		||||
			top: nth($plotDisplayArea, 1);
 | 
			
		||||
			top: $plotLegendH + $interiorMargin;
 | 
			
		||||
			right: auto;
 | 
			
		||||
			bottom: nth($plotDisplayArea, 3);
 | 
			
		||||
			left: 0;
 | 
			
		||||
@@ -202,6 +158,17 @@
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.gl-plot-legend {
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		top: 0;
 | 
			
		||||
		right: 0;
 | 
			
		||||
		bottom: auto;
 | 
			
		||||
		left: 0;
 | 
			
		||||
		height: $plotLegendH;
 | 
			
		||||
		overflow-x: hidden;
 | 
			
		||||
		overflow-y: auto;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/****************************** Limits and Out-of-Bounds data */
 | 
			
		||||
 | 
			
		||||
	.l-limit-bar,
 | 
			
		||||
@@ -268,6 +235,39 @@
 | 
			
		||||
    border: 1px solid $colorPlotAreaBorder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gl-plot-legend,
 | 
			
		||||
.legend {
 | 
			
		||||
	.plot-legend-item,
 | 
			
		||||
	.legend-item {
 | 
			
		||||
		display: inline-block;
 | 
			
		||||
		margin-right: $interiorMarginLg;
 | 
			
		||||
		margin-bottom: $interiorMarginSm;
 | 
			
		||||
		span {
 | 
			
		||||
			vertical-align: middle;
 | 
			
		||||
		}
 | 
			
		||||
		.plot-color-swatch,
 | 
			
		||||
		.color-swatch {
 | 
			
		||||
			border-radius: 2px;
 | 
			
		||||
			display: inline-block;
 | 
			
		||||
			height: $plotSwatchD;
 | 
			
		||||
			width: $plotSwatchD;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gl-plot-legend {
 | 
			
		||||
	.plot-legend-item {
 | 
			
		||||
		border-radius: $smallCr;
 | 
			
		||||
		line-height: 1.5em;
 | 
			
		||||
		padding: 0px $itemPadLR;
 | 
			
		||||
		.plot-color-swatch {
 | 
			
		||||
			border: 1px solid $colorBodyBg;
 | 
			
		||||
			height: $plotSwatchD + 1;
 | 
			
		||||
			width: $plotSwatchD + 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tick {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	border: 0 $colorPlotHash solid;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
ul.tree {
 | 
			
		||||
    @include menuUlReset();
 | 
			
		||||
    @include user-select(none);
 | 
			
		||||
    > li {
 | 
			
		||||
    li {
 | 
			
		||||
        display: block;
 | 
			
		||||
        position: relative;
 | 
			
		||||
    }
 | 
			
		||||
@@ -53,10 +53,12 @@ ul.tree {
 | 
			
		||||
    .view-control {
 | 
			
		||||
        color: $colorItemTreeVC;
 | 
			
		||||
        margin-right: $interiorMargin;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        line-height: inherit;
 | 
			
		||||
        width: $treeVCW;
 | 
			
		||||
        &:before { display: block; }
 | 
			
		||||
        &.no-children {
 | 
			
		||||
            &:before { display: none; }
 | 
			
		||||
        &:before { display: none; }
 | 
			
		||||
        &.has-children {
 | 
			
		||||
            &:before { display: block; }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@
 | 
			
		||||
    $ohH: $btnFrameH;
 | 
			
		||||
    $bc: $colorInteriorBorder;
 | 
			
		||||
    &.child-frame.panel {
 | 
			
		||||
        border: 1px solid transparent;
 | 
			
		||||
        z-index: 0; // Needed to prevent child-frame controls from showing through when another child-frame is above
 | 
			
		||||
        &:not(.no-frame) {
 | 
			
		||||
            background: $colorBodyBg;
 | 
			
		||||
@@ -91,7 +90,7 @@
 | 
			
		||||
 | 
			
		||||
    &.no-frame {
 | 
			
		||||
        background: transparent !important;
 | 
			
		||||
        border: none;
 | 
			
		||||
        border-color: transparent;
 | 
			
		||||
        .object-browse-bar .right {
 | 
			
		||||
            $m: 0;
 | 
			
		||||
            background: rgba(black, 0.3);
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.s-hover-border {
 | 
			
		||||
    border: 1px solid transparent;
 | 
			
		||||
    &:hover {
 | 
			
		||||
        border-color: rgba($colorSelectableSelectedPrimary, 0.5) !important;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<span ng-controller="DateTimeFieldController">
 | 
			
		||||
    <input type="text"
 | 
			
		||||
    <input type="text" autocorrect="off" spellcheck="false"
 | 
			
		||||
           ng-model="textValue"
 | 
			
		||||
           ng-blur="restoreTextValue(); ngBlur()"
 | 
			
		||||
           ng-mouseup="ngMouseup()"
 | 
			
		||||
 
 | 
			
		||||
@@ -83,9 +83,9 @@ define([
 | 
			
		||||
        this.activeObject = domainObject;
 | 
			
		||||
 | 
			
		||||
        if (domainObject && domainObject.hasCapability('composition')) {
 | 
			
		||||
            $(this.toggleView.elements()).removeClass('no-children');
 | 
			
		||||
            $(this.toggleView.elements()).addClass('has-children');
 | 
			
		||||
        } else {
 | 
			
		||||
            $(this.toggleView.elements()).addClass('no-children');
 | 
			
		||||
            $(this.toggleView.elements()).removeClass('has-children');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (domainObject && domainObject.hasCapability('status')) {
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,10 @@ 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()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,11 @@ define(
 | 
			
		||||
                        view.show(container);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        self.providerView = false;
 | 
			
		||||
                        $scope.inspectorKey = selection[0].context.oldItem.getCapability("type").typeDef.inspector;
 | 
			
		||||
                        var selectedItem = selection[0].context.oldItem;
 | 
			
		||||
 | 
			
		||||
                        if (selectedItem) {
 | 
			
		||||
                            $scope.inspectorKey = selectedItem.getCapability("type").typeDef.inspector;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -181,8 +181,6 @@ $colorPlotHash: $colorTick;
 | 
			
		||||
$stylePlotHash: dashed;
 | 
			
		||||
$colorPlotAreaBorder: $colorInteriorBorder;
 | 
			
		||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
 | 
			
		||||
$legendCollapsedNameMaxW: 50%;
 | 
			
		||||
$legendHoverValueBg: rgba($colorBodyFg, 0.1);
 | 
			
		||||
 | 
			
		||||
// Tree
 | 
			
		||||
$colorItemTreeHoverBg: pullForward($colorBodyBg, $hoverRatioPercent);
 | 
			
		||||
 
 | 
			
		||||
@@ -181,8 +181,6 @@ $colorPlotHash: $colorTick;
 | 
			
		||||
$stylePlotHash: dashed;
 | 
			
		||||
$colorPlotAreaBorder: $colorInteriorBorder;
 | 
			
		||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
 | 
			
		||||
$legendCollapsedNameMaxW: 50%;
 | 
			
		||||
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
 | 
			
		||||
 | 
			
		||||
// Tree
 | 
			
		||||
$colorItemTreeHoverBg: pullForward($colorBodyBg, $hoverRatioPercent);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
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");
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
<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>
 | 
			
		||||
@@ -1,169 +0,0 @@
 | 
			
		||||
/*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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,324 +0,0 @@
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,60 +0,0 @@
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,178 +0,0 @@
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,341 +0,0 @@
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
 | 
			
		||||
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));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -45,7 +45,7 @@ define(
 | 
			
		||||
 | 
			
		||||
        FollowIndicator.prototype.getText = function () {
 | 
			
		||||
            var timer = this.timerService.getTimer();
 | 
			
		||||
            return (timer) ? 'Following timer ' + timer.getModel().name : NO_TIMER;
 | 
			
		||||
            return timer ? ('Following timer ' + timer.name) : NO_TIMER;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        FollowIndicator.prototype.getDescription = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -42,18 +42,15 @@ define(["../../src/indicators/FollowIndicator"], function (FollowIndicator) {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe("when a timer is set", function () {
 | 
			
		||||
            var testModel;
 | 
			
		||||
            var mockDomainObject;
 | 
			
		||||
            var testObject;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testModel = { name: "some timer!" };
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj('timer', ['getModel']);
 | 
			
		||||
                mockDomainObject.getModel.andReturn(testModel);
 | 
			
		||||
                mockTimerService.getTimer.andReturn(mockDomainObject);
 | 
			
		||||
                testObject = { name: "some timer!" };
 | 
			
		||||
                mockTimerService.getTimer.andReturn(testObject);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("displays the timer's name", function () {
 | 
			
		||||
                expect(indicator.getText().indexOf(testModel.name))
 | 
			
		||||
                expect(indicator.getText().indexOf(testObject.name))
 | 
			
		||||
                    .not.toEqual(-1);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -272,7 +272,8 @@ define([
 | 
			
		||||
                        "$scope",
 | 
			
		||||
                        "$q",
 | 
			
		||||
                        "dialogService",
 | 
			
		||||
                        "openmct"
 | 
			
		||||
                        "openmct",
 | 
			
		||||
                        "$element"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
@@ -336,6 +337,46 @@ define([
 | 
			
		||||
                            "conversion": "number[]"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "telemetry.panel",
 | 
			
		||||
                    "name": "Telemetry Panel",
 | 
			
		||||
                    "cssClass": "icon-telemetry-panel",
 | 
			
		||||
                    "description": "A panel for collecting telemetry elements.",
 | 
			
		||||
                    "priority": 899,
 | 
			
		||||
                    "delegates": [
 | 
			
		||||
                        "telemetry"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "features": "creation",
 | 
			
		||||
                    "contains": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "has": "telemetry"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "model": {
 | 
			
		||||
                        "composition": []
 | 
			
		||||
                    },
 | 
			
		||||
                    "properties": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "name": "Layout Grid",
 | 
			
		||||
                            "control": "composite",
 | 
			
		||||
                            "items": [
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Horizontal grid (px)",
 | 
			
		||||
                                    "control": "textfield",
 | 
			
		||||
                                    "cssClass": "l-input-sm l-numeric"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Vertical grid (px)",
 | 
			
		||||
                                    "control": "textfield",
 | 
			
		||||
                                    "cssClass": "l-input-sm l-numeric"
 | 
			
		||||
                                }
 | 
			
		||||
                            ],
 | 
			
		||||
                            "pattern": "^(\\d*[1-9]\\d*)?$",
 | 
			
		||||
                            "property": "layoutGrid",
 | 
			
		||||
                            "conversion": "number[]"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
     ng-controller="FixedController as controller">
 | 
			
		||||
 | 
			
		||||
    <!-- Background grid -->
 | 
			
		||||
    <div class="l-grid-holder" ng-click="controller.clearSelection()">
 | 
			
		||||
    <div class="l-grid-holder" ng-click="controller.bypassSelection($event)">
 | 
			
		||||
        <div class="l-grid l-grid-x"
 | 
			
		||||
             ng-if="!controller.getGridSize()[0] < 3"
 | 
			
		||||
             ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
 | 
			
		||||
@@ -35,35 +35,28 @@
 | 
			
		||||
    <!-- 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"
 | 
			
		||||
         ng-click="controller.select(element, $event)">
 | 
			
		||||
         mct-selectable="controller.getContext(element)"
 | 
			
		||||
         mct-init-select="controller.shouldSelect(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.selected()">
 | 
			
		||||
    <span class="s-selected s-moveable" ng-if="controller.isElementSelected()">
 | 
			
		||||
        <div class="l-fixed-position-item t-edit-handle-holder"
 | 
			
		||||
             mct-drag-down="controller.moveHandle().startDrag(controller.selected())"
 | 
			
		||||
             mct-drag-down="controller.moveHandle().startDrag()"
 | 
			
		||||
             mct-drag="controller.moveHandle().continueDrag(delta)"
 | 
			
		||||
             mct-drag-up="controller.moveHandle().endDrag()"
 | 
			
		||||
             ng-style="controller.selected().style"
 | 
			
		||||
             ng-click="$event.stopPropagation()">
 | 
			
		||||
             mct-drag-up="controller.endDrag()"
 | 
			
		||||
             ng-style="controller.getSelectedElementStyle()">
 | 
			
		||||
        </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="handle.endDrag()"
 | 
			
		||||
             ng-click="$event.stopPropagation()">
 | 
			
		||||
             mct-drag-up="controller.endDrag(handle)">
 | 
			
		||||
        </div>
 | 
			
		||||
    </span>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,8 @@
 | 
			
		||||
             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 {{childObject.getId() + '-' + $id}} t-object-type-{{ childObject.getModel().type }}"
 | 
			
		||||
    <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) }"
 | 
			
		||||
         ng-repeat="childObject in composition"
 | 
			
		||||
         ng-init="controller.selectIfNew(childObject.getId() + '-' + $id, childObject)"
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ define(
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {Scope} $scope the controller's Angular scope
 | 
			
		||||
         */
 | 
			
		||||
        function FixedController($scope, $q, dialogService, openmct) {
 | 
			
		||||
        function FixedController($scope, $q, dialogService, openmct, $element) {
 | 
			
		||||
            this.names = {}; // Cache names by ID
 | 
			
		||||
            this.values = {}; // Cache values by ID
 | 
			
		||||
            this.elementProxiesById = {};
 | 
			
		||||
@@ -55,9 +55,11 @@ 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;
 | 
			
		||||
            [
 | 
			
		||||
@@ -87,9 +89,8 @@ define(
 | 
			
		||||
 | 
			
		||||
            // Update the style for a selected element
 | 
			
		||||
            function updateSelectionStyle() {
 | 
			
		||||
                var element = self.selection && self.selection.get();
 | 
			
		||||
                if (element) {
 | 
			
		||||
                    element.style = convertPosition(element);
 | 
			
		||||
                if (self.selectedElementProxy) {
 | 
			
		||||
                    self.selectedElementProxy.style = convertPosition(self.selectedElementProxy);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -136,25 +137,19 @@ define(
 | 
			
		||||
 | 
			
		||||
            // Decorate elements in the current configuration
 | 
			
		||||
            function refreshElements() {
 | 
			
		||||
                // 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);
 | 
			
		||||
                }
 | 
			
		||||
                var elements = (($scope.configuration || {}).elements || []);
 | 
			
		||||
 | 
			
		||||
                // Create the new proxies...
 | 
			
		||||
                self.elementProxies = elements.map(makeProxyElement);
 | 
			
		||||
 | 
			
		||||
                // Clear old selection, and restore if appropriate
 | 
			
		||||
                if (self.selection) {
 | 
			
		||||
                    self.selection.deselect();
 | 
			
		||||
                    if (index > -1) {
 | 
			
		||||
                        self.select(self.elementProxies[index]);
 | 
			
		||||
                // 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;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -224,12 +219,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.");
 | 
			
		||||
@@ -263,21 +258,36 @@ 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;
 | 
			
		||||
 | 
			
		||||
            // 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));
 | 
			
		||||
            this.updateSelectionStyle = updateSelectionStyle;
 | 
			
		||||
 | 
			
		||||
            // Detect changes to grid size
 | 
			
		||||
            $scope.$watch("model.layoutGrid", updateElementPositions);
 | 
			
		||||
@@ -298,10 +308,13 @@ 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));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
@@ -492,42 +505,56 @@ define(
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Check if the element is currently selected, or (if no
 | 
			
		||||
         * argument is supplied) get the currently selected element.
 | 
			
		||||
         * @returns {boolean} true if selected
 | 
			
		||||
         * Checks if the element should be selected or not.
 | 
			
		||||
         *
 | 
			
		||||
         * @param elementProxy the element to check
 | 
			
		||||
         * @returns {boolean} true if the element should be selected.
 | 
			
		||||
         */
 | 
			
		||||
        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, event) {
 | 
			
		||||
            if (event) {
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
        FixedController.prototype.shouldSelect = function (elementProxy) {
 | 
			
		||||
            if (elementProxy.element === this.elementToSelectAfterRefresh) {
 | 
			
		||||
                delete this.elementToSelectAfterRefresh;
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Clear the current user selection.
 | 
			
		||||
         * Checks if an element is currently selected.
 | 
			
		||||
         *
 | 
			
		||||
         * @returns {boolean} true if an element is selected.
 | 
			
		||||
         */
 | 
			
		||||
        FixedController.prototype.clearSelection = function () {
 | 
			
		||||
            if (this.selection) {
 | 
			
		||||
                this.selection.deselect();
 | 
			
		||||
                this.resizeHandles = [];
 | 
			
		||||
                this.mvHandle = undefined;
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -548,6 +575,38 @@ 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 startDrag() {
 | 
			
		||||
        FixedDragHandle.prototype.startDrag = function () {
 | 
			
		||||
            // Cache initial x/y positions
 | 
			
		||||
            this.dragging = {
 | 
			
		||||
                x: this.elementHandle.x(),
 | 
			
		||||
 
 | 
			
		||||
@@ -512,11 +512,10 @@ define(
 | 
			
		||||
         * @param classSelector the css class selector
 | 
			
		||||
         * @param domainObject the domain object
 | 
			
		||||
         */
 | 
			
		||||
        LayoutController.prototype.selectIfNew = function (classSelector, domainObject) {
 | 
			
		||||
        LayoutController.prototype.selectIfNew = function (selector, domainObject) {
 | 
			
		||||
            if (domainObject.getId() === this.droppedIdToSelectAfterRefresh) {
 | 
			
		||||
                var selector = $(classSelector).selector;
 | 
			
		||||
                setTimeout(function () {
 | 
			
		||||
                    $('.' + selector)[0].click();
 | 
			
		||||
                    $('[data-layout-id="' + selector + '"]')[0].click();
 | 
			
		||||
                    delete this.droppedIdToSelectAfterRefresh;
 | 
			
		||||
                }.bind(this), 0);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -77,6 +77,7 @@ 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 {number[]} gridSize the current layout grid size in [x,y] from
 | 
			
		||||
         * @param {Array} elements the full array of elements
 | 
			
		||||
         * @param {number[]} gridSize the current layout grid size in [x,y] from
 | 
			
		||||
         */
 | 
			
		||||
        function ElementProxy(element, index, elements, gridSize) {
 | 
			
		||||
            /**
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,14 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/FixedController"],
 | 
			
		||||
    function (FixedController) {
 | 
			
		||||
    [
 | 
			
		||||
        "../src/FixedController",
 | 
			
		||||
        "zepto"
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        FixedController,
 | 
			
		||||
        $
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        describe("The Fixed Position controller", function () {
 | 
			
		||||
            var mockScope,
 | 
			
		||||
@@ -46,6 +52,9 @@ define(
 | 
			
		||||
                mockMetadata,
 | 
			
		||||
                mockTimeSystem,
 | 
			
		||||
                mockLimitEvaluator,
 | 
			
		||||
                mockSelection,
 | 
			
		||||
                $element = [],
 | 
			
		||||
                selectable = [],
 | 
			
		||||
                controller;
 | 
			
		||||
 | 
			
		||||
            // Utility function; find a watch for a given expression
 | 
			
		||||
@@ -180,17 +189,30 @@ define(
 | 
			
		||||
 | 
			
		||||
                mockScope.model = testModel;
 | 
			
		||||
                mockScope.configuration = testConfiguration;
 | 
			
		||||
                mockScope.selection = jasmine.createSpyObj(
 | 
			
		||||
                    'selection',
 | 
			
		||||
                    ['select', 'get', 'selected', 'deselect', 'proxy']
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                selectable[0] = {
 | 
			
		||||
                    context: {
 | 
			
		||||
                        oldItem: mockDomainObject
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                mockSelection = jasmine.createSpyObj("selection", [
 | 
			
		||||
                    'select',
 | 
			
		||||
                    'on',
 | 
			
		||||
                    'off',
 | 
			
		||||
                    'get'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockSelection.get.andCallThrough();
 | 
			
		||||
 | 
			
		||||
                mockOpenMCT = {
 | 
			
		||||
                    time: mockConductor,
 | 
			
		||||
                    telemetry: mockTelemetryAPI,
 | 
			
		||||
                    composition: mockCompositionAPI
 | 
			
		||||
                    composition: mockCompositionAPI,
 | 
			
		||||
                    selection: mockSelection
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                $element = $('<div></div>');
 | 
			
		||||
                spyOn($element[0], 'click');
 | 
			
		||||
 | 
			
		||||
                mockMetadata = jasmine.createSpyObj('mockMetadata', [
 | 
			
		||||
                    'valuesForHints',
 | 
			
		||||
                    'value',
 | 
			
		||||
@@ -226,11 +248,11 @@ define(
 | 
			
		||||
                    mockScope,
 | 
			
		||||
                    mockQ,
 | 
			
		||||
                    mockDialogService,
 | 
			
		||||
                    mockOpenMCT
 | 
			
		||||
                    mockOpenMCT,
 | 
			
		||||
                    $element
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                findWatch("model.layoutGrid")(testModel.layoutGrid);
 | 
			
		||||
                findWatch("selection")(mockScope.selection);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("subscribes when a domain object is available", function () {
 | 
			
		||||
@@ -306,41 +328,41 @@ define(
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows elements to be selected", function () {
 | 
			
		||||
                var elements;
 | 
			
		||||
 | 
			
		||||
                testModel.modified = 1;
 | 
			
		||||
                findWatch("model.modified")(testModel.modified);
 | 
			
		||||
 | 
			
		||||
                elements = controller.getElements();
 | 
			
		||||
                controller.select(elements[1]);
 | 
			
		||||
                expect(mockScope.selection.select)
 | 
			
		||||
                    .toHaveBeenCalledWith(elements[1]);
 | 
			
		||||
                selectable[0].context.elementProxy = controller.getElements()[1];
 | 
			
		||||
                mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
 | 
			
		||||
 | 
			
		||||
                expect(controller.isElementSelected()).toBe(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows selection retrieval", function () {
 | 
			
		||||
                // selected with no arguments should give the current
 | 
			
		||||
                // selection
 | 
			
		||||
                var elements;
 | 
			
		||||
 | 
			
		||||
                testModel.modified = 1;
 | 
			
		||||
                findWatch("model.modified")(testModel.modified);
 | 
			
		||||
 | 
			
		||||
                elements = controller.getElements();
 | 
			
		||||
                controller.select(elements[1]);
 | 
			
		||||
                mockScope.selection.get.andReturn(elements[1]);
 | 
			
		||||
                expect(controller.selected()).toEqual(elements[1]);
 | 
			
		||||
                selectable[0].context.elementProxy = elements[1];
 | 
			
		||||
                mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
 | 
			
		||||
 | 
			
		||||
                expect(controller.getSelectedElement()).toEqual(elements[1]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows selections to be cleared", function () {
 | 
			
		||||
                var elements;
 | 
			
		||||
 | 
			
		||||
            it("selects the parent view when selected element is removed", function () {
 | 
			
		||||
                testModel.modified = 1;
 | 
			
		||||
                findWatch("model.modified")(testModel.modified);
 | 
			
		||||
 | 
			
		||||
                elements = controller.getElements();
 | 
			
		||||
                controller.select(elements[1]);
 | 
			
		||||
                controller.clearSelection();
 | 
			
		||||
                expect(controller.selected(elements[1])).toBeFalsy();
 | 
			
		||||
                var elements = controller.getElements();
 | 
			
		||||
                selectable[0].context.elementProxy = elements[1];
 | 
			
		||||
                mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
 | 
			
		||||
 | 
			
		||||
                elements[1].remove();
 | 
			
		||||
                testModel.modified = 2;
 | 
			
		||||
                findWatch("model.modified")(testModel.modified);
 | 
			
		||||
 | 
			
		||||
                expect($element[0].click).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("retains selections during refresh", function () {
 | 
			
		||||
@@ -352,23 +374,21 @@ define(
 | 
			
		||||
                findWatch("model.modified")(testModel.modified);
 | 
			
		||||
 | 
			
		||||
                elements = controller.getElements();
 | 
			
		||||
                controller.select(elements[1]);
 | 
			
		||||
                selectable[0].context.elementProxy = elements[1];
 | 
			
		||||
                mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
 | 
			
		||||
 | 
			
		||||
                // Verify precondition
 | 
			
		||||
                expect(mockScope.selection.select.calls.length).toEqual(1);
 | 
			
		||||
 | 
			
		||||
                // Mimic selection behavior
 | 
			
		||||
                mockScope.selection.get.andReturn(elements[1]);
 | 
			
		||||
                expect(controller.getSelectedElement()).toEqual(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(mockScope.selection.select.calls.length).toEqual(2);
 | 
			
		||||
                expect(controller.shouldSelect(elements[1])).toBe(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("Displays received values for telemetry elements", function () {
 | 
			
		||||
@@ -505,21 +525,25 @@ define(
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("exposes a view-level selection proxy", function () {
 | 
			
		||||
                expect(mockScope.selection.proxy).toHaveBeenCalledWith(
 | 
			
		||||
                    jasmine.any(Object)
 | 
			
		||||
                );
 | 
			
		||||
                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();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("exposes drag handles", function () {
 | 
			
		||||
                var handles;
 | 
			
		||||
 | 
			
		||||
                // Select something so that drag handles are expected
 | 
			
		||||
                testModel.modified = 1;
 | 
			
		||||
                findWatch("model.modified")(testModel.modified);
 | 
			
		||||
                controller.select(controller.getElements()[1]);
 | 
			
		||||
 | 
			
		||||
                selectable[0].context.elementProxy = controller.getElements()[1];
 | 
			
		||||
                mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
 | 
			
		||||
 | 
			
		||||
                // Should have a non-empty array of handles
 | 
			
		||||
                handles = controller.handles();
 | 
			
		||||
 | 
			
		||||
                expect(handles).toEqual(jasmine.any(Array));
 | 
			
		||||
                expect(handles.length).not.toEqual(0);
 | 
			
		||||
 | 
			
		||||
@@ -532,15 +556,14 @@ 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);
 | 
			
		||||
                controller.select(controller.getElements()[1]);
 | 
			
		||||
 | 
			
		||||
                selectable[0].context.elementProxy = controller.getElements()[1];
 | 
			
		||||
                mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
 | 
			
		||||
 | 
			
		||||
                // Should have a move handle
 | 
			
		||||
                handle = controller.moveHandle();
 | 
			
		||||
                var handle = controller.moveHandle();
 | 
			
		||||
 | 
			
		||||
                // And it should have start/continue/end drag methods
 | 
			
		||||
                expect(handle.startDrag).toEqual(jasmine.any(Function));
 | 
			
		||||
@@ -551,26 +574,40 @@ 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);
 | 
			
		||||
                controller.select(controller.getElements()[1]);
 | 
			
		||||
                mockScope.selection.get.andReturn(controller.getElements()[1]);
 | 
			
		||||
 | 
			
		||||
                selectable[0].context.elementProxy = controller.getElements()[1];
 | 
			
		||||
                mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
 | 
			
		||||
 | 
			
		||||
                // Get style
 | 
			
		||||
                oldStyle = controller.selected().style;
 | 
			
		||||
                oldStyle = controller.getSelectedElementStyle();
 | 
			
		||||
 | 
			
		||||
                // Start a drag gesture
 | 
			
		||||
                controller.moveHandle().startDrag();
 | 
			
		||||
 | 
			
		||||
                // Haven't moved yet; style shouldn't have updated yet
 | 
			
		||||
                expect(controller.selected().style).toEqual(oldStyle);
 | 
			
		||||
                expect(controller.getSelectedElementStyle()).toEqual(oldStyle);
 | 
			
		||||
 | 
			
		||||
                // Drag a little
 | 
			
		||||
                controller.moveHandle().continueDrag([1000, 100]);
 | 
			
		||||
 | 
			
		||||
                // Style should have been updated
 | 
			
		||||
                expect(controller.selected().style).not.toEqual(oldStyle);
 | 
			
		||||
                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)
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            describe("on display bounds changes", function () {
 | 
			
		||||
@@ -702,6 +739,14 @@ 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,8 +21,14 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/LayoutController"],
 | 
			
		||||
    function (LayoutController) {
 | 
			
		||||
    [
 | 
			
		||||
        "../src/LayoutController",
 | 
			
		||||
        "zepto"
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        LayoutController,
 | 
			
		||||
        $
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        describe("The Layout controller", function () {
 | 
			
		||||
            var mockScope,
 | 
			
		||||
@@ -35,6 +41,7 @@ define(
 | 
			
		||||
                mockCompositionObjects,
 | 
			
		||||
                mockOpenMCT,
 | 
			
		||||
                mockSelection,
 | 
			
		||||
                mockDomainObjectCapability,
 | 
			
		||||
                $element = [],
 | 
			
		||||
                selectable = [];
 | 
			
		||||
 | 
			
		||||
@@ -62,6 +69,14 @@ define(
 | 
			
		||||
                        } else {
 | 
			
		||||
                            return {};
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    getCapability: function () {
 | 
			
		||||
                        return mockDomainObjectCapability;
 | 
			
		||||
                    },
 | 
			
		||||
                    hasCapability: function (param) {
 | 
			
		||||
                        if (param === 'composition') {
 | 
			
		||||
                            return id !== 'b';
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
@@ -89,7 +104,9 @@ define(
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                mockDomainObjectCapability = jasmine.createSpyObj('capability',
 | 
			
		||||
                    ['inEditContext']
 | 
			
		||||
                );
 | 
			
		||||
                mockCompositionCapability = mockPromise(mockCompositionObjects);
 | 
			
		||||
 | 
			
		||||
                mockScope.domainObject = mockDomainObject("mockDomainObject");
 | 
			
		||||
@@ -98,7 +115,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                selectable[0] = {
 | 
			
		||||
                    context: {
 | 
			
		||||
                        oldItem: mockDomainObject
 | 
			
		||||
                        oldItem: mockScope.domainObject
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
@@ -112,10 +129,10 @@ define(
 | 
			
		||||
                mockOpenMCT = {
 | 
			
		||||
                    selection: mockSelection
 | 
			
		||||
                };
 | 
			
		||||
                $element[0] = jasmine.createSpyObj(
 | 
			
		||||
                    "$element",
 | 
			
		||||
                    ['click']
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                $element = $('<div></div>');
 | 
			
		||||
                $(document).find('body').append($element);
 | 
			
		||||
                spyOn($element[0], 'click');
 | 
			
		||||
 | 
			
		||||
                spyOn(mockScope.domainObject, "useCapability").andCallThrough();
 | 
			
		||||
 | 
			
		||||
@@ -125,6 +142,11 @@ define(
 | 
			
		||||
                jasmine.Clock.useMock();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            afterEach(function () {
 | 
			
		||||
                $element.remove();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            it("listens for selection change events", function () {
 | 
			
		||||
                expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
 | 
			
		||||
                    'change',
 | 
			
		||||
@@ -427,6 +449,41 @@ define(
 | 
			
		||||
                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();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										333
									
								
								platform/features/notebook/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								platform/features/notebook/bundle.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,333 @@
 | 
			
		||||
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"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "stylesheetUrl": "css/notebook-espresso.css",
 | 
			
		||||
                    "theme": "espresso"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "stylesheetUrl": "css/notebook-snow.css",
 | 
			
		||||
                    "theme": "snow"
 | 
			
		||||
                }
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										334
									
								
								platform/features/notebook/res/sass/_notebook-base.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								platform/features/notebook/res/sass/_notebook-base.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,334 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.w-notebook {
 | 
			
		||||
    //@include test($a: 0.1);
 | 
			
		||||
    //display: flex;
 | 
			
		||||
    //flex-direction: column;
 | 
			
		||||
    //flex-wrap: nowrap;
 | 
			
		||||
    font-size: 0.8rem;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0px;
 | 
			
		||||
    right: 0px;
 | 
			
		||||
    bottom: 0px;
 | 
			
		||||
    left: 0px;
 | 
			
		||||
    width: auto;
 | 
			
		||||
    height: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mct-notebook {
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-notebook-drag-area {
 | 
			
		||||
    padding: 10px 0;
 | 
			
		||||
    //margin: 15px 0;
 | 
			
		||||
    font-style: italic;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    .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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.w-notebook-entries {
 | 
			
		||||
    //@include test($a: 0.1);
 | 
			
		||||
    padding-right: $interiorMarginSm;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    overflow-x: hidden;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
    .t-entries-list {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-notebook-entry {
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    margin-bottom: $interiorMarginSm;
 | 
			
		||||
    padding: $interiorMargin $interiorMarginLg;
 | 
			
		||||
 | 
			
		||||
    &:hover {
 | 
			
		||||
        .entry-content .entry-text{
 | 
			
		||||
            .unedited-text{
 | 
			
		||||
                //display: none;
 | 
			
		||||
            }
 | 
			
		||||
            textarea{
 | 
			
		||||
                //background-color: $colorBodyBg;
 | 
			
		||||
                min-height: 50px;
 | 
			
		||||
                height: auto;
 | 
			
		||||
                resize: none;
 | 
			
		||||
                //display: block;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    &.active {
 | 
			
		||||
        background-color: rgba(red, 0.5);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .entry-time{
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .entry-content{
 | 
			
		||||
        //flex: 4 1 0;
 | 
			
		||||
        //padding: 0 15px;
 | 
			
		||||
        //min-height: 65px;
 | 
			
		||||
        .entry-embeds{
 | 
			
		||||
            flex-wrap: wrap;
 | 
			
		||||
        }
 | 
			
		||||
        .snap-thumb {
 | 
			
		||||
            cursor: pointer;
 | 
			
		||||
        }
 | 
			
		||||
        .entry-text {
 | 
			
		||||
            display: block;
 | 
			
		||||
 | 
			
		||||
            .s-entry-input {
 | 
			
		||||
                background-color: rgba(black, 0.1);
 | 
			
		||||
                padding: 2px;
 | 
			
		||||
                &:active {
 | 
			
		||||
                    background-color: red;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .s-entry-input {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    .entry-delete{
 | 
			
		||||
        //padding: 0 15px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-entry-embed {
 | 
			
		||||
    $m: $interiorMargin;
 | 
			
		||||
    margin: 0 $m $m 0;
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
    &:not(.has-snapshot) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.has-snapshot {
 | 
			
		||||
        &:before {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            top: $m;
 | 
			
		||||
            left: $m;
 | 
			
		||||
            text-shadow: rgba(black, 0.7) 0 1px 5px;
 | 
			
		||||
            z-index: 2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    .snap-thumb {
 | 
			
		||||
        $d: 50px;
 | 
			
		||||
        width: $d;
 | 
			
		||||
        height: $d;
 | 
			
		||||
        border-radius: 5px;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        img {
 | 
			
		||||
            height: 100%;
 | 
			
		||||
            width: 100%;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .embed-info {
 | 
			
		||||
        margin-left: $interiorMargin;
 | 
			
		||||
        .embed-title {
 | 
			
		||||
            font-weight: bold;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.t-contents,
 | 
			
		||||
.snap-annotation {
 | 
			
		||||
    // Todo: don't write this to t-contents, add a l- class
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    img{
 | 
			
		||||
        width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.notebook-filters{
 | 
			
		||||
    .select{
 | 
			
		||||
        margin-left: 10px;
 | 
			
		||||
        border-radius: 5px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/********************************************* SNAPSHOT VIEWING IN OVERLAY CONTEXT */
 | 
			
		||||
.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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ptro-color-main{
 | 
			
		||||
    top: 0;
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    height: auto;
 | 
			
		||||
    min-height: 41px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ptro-wrapper{
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    top: 40px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/********************************************* New Notebook Entry from Large View overlay */
 | 
			
		||||
.notebook-button-container {
 | 
			
		||||
    //margin-right: $interiorMargin; // TODO: change to apply margin-left to view switcher button in Large View
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/********************************************* NO IDEA WHAT THERE ARE APPLYING TO */
 | 
			
		||||
.context-available {
 | 
			
		||||
    outline: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menu-element.menu-view{
 | 
			
		||||
    z-index: 999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.t-console {
 | 
			
		||||
    // Temp console-like reporting element
 | 
			
		||||
    max-height: 200px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*@media screen and (max-width: 1024px){
 | 
			
		||||
    .w-notebook-entries{
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										59
									
								
								platform/features/notebook/res/sass/_notebook-thematic.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								platform/features/notebook/res/sass/_notebook-thematic.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
.s-notebook-entry {
 | 
			
		||||
    background-color: rgba($colorBodyFg, 0.1);
 | 
			
		||||
    border-radius: $basicCr;
 | 
			
		||||
    &:hover {
 | 
			
		||||
        background-color: rgba($colorBodyFg, 0.2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .entry-time{
 | 
			
		||||
        color: rgba($colorBodyFg, 0.5);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.l-notebook-drag-area {
 | 
			
		||||
    border: 1px dashed $colorKey;
 | 
			
		||||
    border-radius: $controlCr;
 | 
			
		||||
    &.drag-active{
 | 
			
		||||
        border-color: $colorKey;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-entry-embed {
 | 
			
		||||
    &.has-snapshot {
 | 
			
		||||
        &:before {
 | 
			
		||||
            color: $colorBodyFg;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.snapshot {
 | 
			
		||||
    background: $colorBodyBg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.snap-thumb {
 | 
			
		||||
    border: 1px solid $colorInteriorBorder;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								platform/features/notebook/res/sass/notebook-espresso.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								platform/features/notebook/res/sass/notebook-espresso.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
$output-bourbon-deprecation-warnings: false;
 | 
			
		||||
@import "bourbon";
 | 
			
		||||
 | 
			
		||||
@import "../../../../commonUI/general/res/sass/constants";
 | 
			
		||||
@import "../../../../commonUI/general/res/sass/mixins";
 | 
			
		||||
@import "../../../../commonUI/general/res/sass/glyphs";
 | 
			
		||||
@import "../../../../commonUI/themes/espresso/res/sass/constants";
 | 
			
		||||
@import "../../../../commonUI/themes/espresso/res/sass/mixins";
 | 
			
		||||
//@import "constants";
 | 
			
		||||
//@import "constants-espresso";
 | 
			
		||||
@import "notebook-thematic";
 | 
			
		||||
							
								
								
									
										32
									
								
								platform/features/notebook/res/sass/notebook-snow.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								platform/features/notebook/res/sass/notebook-snow.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
$output-bourbon-deprecation-warnings: false;
 | 
			
		||||
@import "bourbon";
 | 
			
		||||
 | 
			
		||||
@import "../../../../commonUI/general/res/sass/constants";
 | 
			
		||||
@import "../../../../commonUI/general/res/sass/mixins";
 | 
			
		||||
@import "../../../../commonUI/general/res/sass/glyphs";
 | 
			
		||||
@import "../../../../commonUI/themes/snow/res/sass/constants";
 | 
			
		||||
@import "../../../../commonUI/themes/snow/res/sass/mixins";
 | 
			
		||||
//@import "constants";
 | 
			
		||||
//@import "constants-snow";
 | 
			
		||||
@import "notebook-thematic";
 | 
			
		||||
							
								
								
									
										26
									
								
								platform/features/notebook/res/sass/notebook.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								platform/features/notebook/res/sass/notebook.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 "../../../../commonUI/general/res/sass/constants";
 | 
			
		||||
@import "../../../../commonUI/general/res/sass/mixins";
 | 
			
		||||
@import "notebook-base";
 | 
			
		||||
							
								
								
									
										2
									
								
								platform/features/notebook/res/templates/annotation.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								platform/features/notebook/res/templates/annotation.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
<div class="snap-annotation" id="snap-annotation" ng-init="ngModel.tracker()">
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
<!--
 | 
			
		||||
 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.
 | 
			
		||||
-->
 | 
			
		||||
<!--
 | 
			
		||||
This element appears in the overlay dialog when initiating a new Notebook Entry from a view's Notebook button -->
 | 
			
		||||
<div class='form-control'>
 | 
			
		||||
    <ng-form name="mctControl">
 | 
			
		||||
        <div class='fields' ng-controller="NewEntryController">
 | 
			
		||||
            <div class="l-flex-row new-notebook-entry-embed l-entry-embed {{cssClass}}"
 | 
			
		||||
                 ng-class="{ 'has-snapshot' : snapToggle }">
 | 
			
		||||
                <div class="holder flex-elem snap-thumb"
 | 
			
		||||
                    ng-if="snapToggle">
 | 
			
		||||
                    <img ng-src="{{snapshot.src}}" alt="{{snapshot.modified}}">
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="holder flex-elem embed-info">
 | 
			
		||||
                    <div class="embed-title">{{objectName}}</div>
 | 
			
		||||
                    <div class="embed-date"
 | 
			
		||||
                         ng-if="snapToggle">{{snapshot.modified| date:'yyyy-MM-dd HH:mm:ss'}}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="holder flex-elem annotate-new"
 | 
			
		||||
                     ng-if="snapToggle">
 | 
			
		||||
                    <a class="s-button flex-elem icon-pencil "
 | 
			
		||||
                       title="Annotate this snapshot"
 | 
			
		||||
                       ng-click="annotateSnapshot()">
 | 
			
		||||
                        <span class="title-label">Annotate</span>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </ng-form>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
<!--
 | 
			
		||||
 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>
 | 
			
		||||
							
								
								
									
										38
									
								
								platform/features/notebook/res/templates/entry.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								platform/features/notebook/res/templates/entry.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
<!--
 | 
			
		||||
 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>
 | 
			
		||||
@@ -0,0 +1,54 @@
 | 
			
		||||
<!--
 | 
			
		||||
 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>
 | 
			
		||||
							
								
								
									
										84
									
								
								platform/features/notebook/res/templates/layoutNotebook.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								platform/features/notebook/res/templates/layoutNotebook.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
<!--
 | 
			
		||||
 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>
 | 
			
		||||
							
								
								
									
										132
									
								
								platform/features/notebook/res/templates/notebook.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								platform/features/notebook/res/templates/notebook.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
<div ng-controller="NotebookController as controller" class="mct-notebook w-notebook l-flex-col">
 | 
			
		||||
    <div class="l-notebook-head holder l-flex-row flex-elem">
 | 
			
		||||
        <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="holder flex-elem l-flex-row l-notebook-drag-area icon-plus" ng-click="newEntry($event)" id="newEntry" mct-entry-dnd>
 | 
			
		||||
        <span class="label">To start a new entry, click here or drag and drop any object</span>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- entries -->
 | 
			
		||||
    <div class="holder flex-elem grows w-notebook-entries t-entries-list" ng-mouseover="handleActive()">
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li class="l-flex-row l-notebook-entry s-notebook-entry"
 | 
			
		||||
              id="{{'entry_'+ entry.id}}"
 | 
			
		||||
              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="holder flex-elem entry-time">
 | 
			
		||||
                <span>{{entry.createdOn | date:'yyyy-MM-dd'}}</span>
 | 
			
		||||
                <span>{{entry.createdOn | date:'HH:mm:ss'}}</span>
 | 
			
		||||
                <!--<div>{{'entry_'+entry.id}}</div>-->
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="holder flex-elem l-flex-col grows entry-content">
 | 
			
		||||
                <div class="holder flex-elem entry-text">
 | 
			
		||||
                    <!--<div>Rows: {{parseText(entry.text).length}} Chars: {{entry.text.length}}</div>
 | 
			
		||||
                    <div class="unedited-text">
 | 
			
		||||
                        <p ng-repeat="line in parseText(entry.text) track by $index">{{line}}</p>
 | 
			
		||||
                    </div>-->
 | 
			
		||||
                    <div contenteditable="true"
 | 
			
		||||
                        ng-blur="textBlur($event, entry.id)"
 | 
			
		||||
                        ng-focus="textFocus($event, entry.id)"
 | 
			
		||||
                        ng-model="entry.text"
 | 
			
		||||
                        placeholder="Enter text here"
 | 
			
		||||
                        class="t-entry-input s-entry-input">
 | 
			
		||||
                        {{entry.text}}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <!-- embeds -->
 | 
			
		||||
                <div class="holder flex-elem entry-embeds l-flex-row">
 | 
			
		||||
                    <div class="l-flex-row l-entry-embed {{embed.cssClass}}"
 | 
			
		||||
                         ng-repeat="embed in entry.embeds track by $index"
 | 
			
		||||
                         ng-class="{ 'has-snapshot' : embed.snapshot }"
 | 
			
		||||
                         id="{{embed.id}}">
 | 
			
		||||
                        <!--<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 ng-click='navigate($event,embed.type)'>{{embed.name}}</a>
 | 
			
		||||
                                <a 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"
 | 
			
		||||
                                 ng-if="embed.snapshot">{{embed.id| date:'yyyy-MM-dd HH:mm:ss'}}</div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <!-- delete entry -->
 | 
			
		||||
            <div class="holder flex-elem entry-delete">
 | 
			
		||||
              <a class="s-icon-button icon-trash" title="Delete Entry" ng-click="deleteEntry($event)"></a>
 | 
			
		||||
            </div>
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
<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>
 | 
			
		||||
							
								
								
									
										111
									
								
								platform/features/notebook/src/actions/AnnotateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								platform/features/notebook/src/actions/AnnotateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										65
									
								
								platform/features/notebook/src/actions/CreateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								platform/features/notebook/src/actions/CreateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										191
									
								
								platform/features/notebook/src/actions/NewEntryContextual.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								platform/features/notebook/src/actions/NewEntryContextual.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										72
									
								
								platform/features/notebook/src/actions/RemoveEmbed.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								platform/features/notebook/src/actions/RemoveEmbed.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										74
									
								
								platform/features/notebook/src/actions/RemoveSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								platform/features/notebook/src/actions/RemoveSnapshot.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										160
									
								
								platform/features/notebook/src/actions/ViewSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								platform/features/notebook/src/actions/ViewSnapshot.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,50 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,54 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										365
									
								
								platform/features/notebook/src/controllers/NotebookController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								platform/features/notebook/src/controllers/NotebookController.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,365 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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('.t-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.reportModel = function () {
 | 
			
		||||
                var entries = $scope.domainObject.model.entries;
 | 
			
		||||
                // console.log("REPORT_MODEL:");
 | 
			
		||||
                // console.log(entries.length + " entries");
 | 
			
		||||
                for (var i=0; i<entries.length; i++) {
 | 
			
		||||
                    var cEntry = entries[i];
 | 
			
		||||
                    // console.log(cEntry.id + ": " + cEntry.createdOn + " / " + cEntry.text);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $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();
 | 
			
		||||
                $scope.reportModel();
 | 
			
		||||
                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) {
 | 
			
		||||
                        var id = now();
 | 
			
		||||
                        model.entries.push({'id': id, 'createdOn': id});
 | 
			
		||||
                    });
 | 
			
		||||
                } else {
 | 
			
		||||
                    $scope.domainObject.useCapability('mutation', function (model) {
 | 
			
		||||
                        model.entries[entries.length - 1].createdOn = now();
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                $scope.entrySearch = '';
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /*--delete an entry--*/
 | 
			
		||||
            $scope.deleteEntry = function ($event) {
 | 
			
		||||
                /* This is really brittle - change the markup and this doesn't work */
 | 
			
		||||
                var delId = $event.currentTarget.parentElement.parentElement.id;
 | 
			
		||||
                // console.log("Trying to delete " + delId);
 | 
			
		||||
                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.id;
 | 
			
		||||
                            }).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, entryId) {
 | 
			
		||||
                // if ($event.currentTarget && $event.currentTarget.innerText) {
 | 
			
		||||
                    /*
 | 
			
		||||
                     On focus, if the currentTarget isn't blank, set the global currentEntryValue = the
 | 
			
		||||
                     content of the current focus. This will be used at blur to determine if the
 | 
			
		||||
                     current entry has been modified or not.
 | 
			
		||||
                     Not sure this is right, would think we'd always want to set curEntVal even if blank
 | 
			
		||||
                     */
 | 
			
		||||
                    $scope.currentEntryValue = $event.currentTarget.innerText;
 | 
			
		||||
                // }
 | 
			
		||||
                // console.log('focus: ' + entryId + '; currentEntryValue: ' + $scope.currentEntryValue);
 | 
			
		||||
                // console.log('----');
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            $scope.textBlur = function ($event, entryId) {
 | 
			
		||||
                // entryId is the unique numeric based on the original createdOn
 | 
			
		||||
                if ($event.target && $event.target.innerText !== "") {
 | 
			
		||||
                    var elementPos = $scope.domainObject.model.entries.map(function (x) {
 | 
			
		||||
                        return x.id;
 | 
			
		||||
                    }).indexOf(+(entryId));
 | 
			
		||||
 | 
			
		||||
                    // If the text of an entry has been changed, then update the text and the createdOn numeric
 | 
			
		||||
                    // Otherwise, don't do anything
 | 
			
		||||
                    if ($scope.currentEntryValue !== $event.target.innerText) {
 | 
			
		||||
                        $scope.domainObject.useCapability('mutation', function (model) {
 | 
			
		||||
                            model.entries[elementPos].text = $event.target.innerText;
 | 
			
		||||
                            model.entries[elementPos].createdOn = now();
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
/*                    $scope.domainObject.useCapability('mutation', function (model) {
 | 
			
		||||
                        model.entries[elementPos].text = $event.target.innerText;
 | 
			
		||||
                        if ($scope.currentEntryValue !== $event.target.innerText) {
 | 
			
		||||
                            model.entries[elementPos].createdOn = now();
 | 
			
		||||
                        }
 | 
			
		||||
                    });*/
 | 
			
		||||
                }
 | 
			
		||||
                // console.log('blur: ' + entryId + '; currentEntryValue: ' + $scope.currentEntryValue);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            $scope.finished = function (model) {
 | 
			
		||||
                var lastEntry = model[model.length - 1];
 | 
			
		||||
                if (!lastEntry.text) {
 | 
			
		||||
                    var newEntry = $scope.entriesEl.find('#entry_' + lastEntry.id).addClass('active');
 | 
			
		||||
                    newEntry.find('.t-entry-input').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;
 | 
			
		||||
    });
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										140
									
								
								platform/features/notebook/src/directives/EntryDnd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								platform/features/notebook/src/directives/EntryDnd.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										164
									
								
								platform/features/notebook/src/directives/MCTModalNotebook.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								platform/features/notebook/src/directives/MCTModalNotebook.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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_BUTTON_TEMPLATE = '<a class="s-button labeled 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_BUTTON_TEMPLATE;
 | 
			
		||||
                    notebookButton = frame.querySelector('.object-browse-bar .right');
 | 
			
		||||
                    notebookButton.prepend(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;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										134
									
								
								platform/features/notebook/src/directives/MCTSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								platform/features/notebook/src/directives/MCTSnapshot.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										44
									
								
								platform/features/notebook/src/policies/CompositionPolicy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								platform/features/notebook/src/policies/CompositionPolicy.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * 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 "containment" rules, which determine which objects
 | 
			
		||||
 * can be contained within a notebook.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        function CompositionPolicy() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CompositionPolicy.prototype.allow = function (parent, child) {
 | 
			
		||||
            var parentDef = parent.getCapability('type').getName();
 | 
			
		||||
 | 
			
		||||
            if (parentDef === 'Notebook' && child.getCapability('status').list().length) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return CompositionPolicy;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										40
									
								
								platform/features/notebook/src/policies/ViewPolicy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								platform/features/notebook/src/policies/ViewPolicy.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 ViewPolicy() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ViewPolicy.prototype.allow = function (view, domainObject) {
 | 
			
		||||
            if (view.key === 'layout') {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return ViewPolicy;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								platform/features/plot/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								platform/features/plot/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
# Plot README
 | 
			
		||||
 | 
			
		||||
## Chart 
 | 
			
		||||
 | 
			
		||||
The `mct-chart` directive is used to support drawing of simple charts. It is 
 | 
			
		||||
present to support the Plot view, and its functionality is limited to the 
 | 
			
		||||
functionality that is relevant for that view.
 | 
			
		||||
 | 
			
		||||
This directive is used at the element level and takes one attribute, `draw` 
 | 
			
		||||
which is an Angular expression which will should evaluate to a drawing object. 
 | 
			
		||||
This drawing object should contain the following properties:
 | 
			
		||||
 | 
			
		||||
* `dimensions`: The size, in logical coordinates, of the chart area. A 
 | 
			
		||||
two-element array or numbers. 
 | 
			
		||||
* `origin`: The position, in logical coordinates, of the lower-left corner of 
 | 
			
		||||
the chart area. A two-element array or numbers. 
 | 
			
		||||
* `lines`: An array of lines (e.g. as a plot line) to draw, where each line is 
 | 
			
		||||
expressed as an object containing: 
 | 
			
		||||
    * `buffer`: A Float32Array containing points in the line, in logical 
 | 
			
		||||
    coordinates, in sequential x,y pairs. 
 | 
			
		||||
    * `color`: The color of the line, as a four-element RGBA array, where 
 | 
			
		||||
    each element is a number in the range of 0.0-1.0. 
 | 
			
		||||
    * `points`: The number of points in the line. 
 | 
			
		||||
* `boxes`: An array of rectangles to draw in the chart area. Each is an object 
 | 
			
		||||
containing: 
 | 
			
		||||
    * `start`: The first corner of the rectangle, as a two-element array of 
 | 
			
		||||
    numbers, in logical coordinates. 
 | 
			
		||||
    * `end`: The opposite corner of the rectangle, as a two-element array of 
 | 
			
		||||
    numbers, in logical coordinates. color : The color of the line, as a 
 | 
			
		||||
    four-element RGBA array, where each element is a number in the range of 
 | 
			
		||||
    0.0-1.0. 
 | 
			
		||||
 | 
			
		||||
While `mct-chart` is intended to support plots specifically, it does perform 
 | 
			
		||||
some useful management of canvas objects (e.g. choosing between WebGL and Canvas 
 | 
			
		||||
2D APIs for drawing based on browser support) so its usage is recommended when 
 | 
			
		||||
its supported drawing primitives are sufficient for other charting tasks. 
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										157
									
								
								platform/features/plot/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								platform/features/plot/bundle.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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([
 | 
			
		||||
    "./src/MCTChart",
 | 
			
		||||
    "./src/PlotController",
 | 
			
		||||
    "./src/policies/PlotViewPolicy",
 | 
			
		||||
    "./src/PlotOptionsController",
 | 
			
		||||
    "./src/services/ExportImageService",
 | 
			
		||||
    "text!./res/templates/plot.html",
 | 
			
		||||
    "text!./res/templates/plot-options-browse.html",
 | 
			
		||||
    'legacyRegistry'
 | 
			
		||||
], function (
 | 
			
		||||
    MCTChart,
 | 
			
		||||
    PlotController,
 | 
			
		||||
    PlotViewPolicy,
 | 
			
		||||
    PlotOptionsController,
 | 
			
		||||
    exportImageService,
 | 
			
		||||
    plotTemplate,
 | 
			
		||||
    plotOptionsBrowseTemplate,
 | 
			
		||||
    legacyRegistry
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    legacyRegistry.register("platform/features/plot", {
 | 
			
		||||
        "name": "Plot view for telemetry",
 | 
			
		||||
        "extensions": {
 | 
			
		||||
            "views": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Plot",
 | 
			
		||||
                    "key": "plot",
 | 
			
		||||
                    "cssClass": "icon-sine",
 | 
			
		||||
                    "template": plotTemplate,
 | 
			
		||||
                    "needs": [
 | 
			
		||||
                        "telemetry"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "priority": "preferred",
 | 
			
		||||
                    "delegation": true
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "directives": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "mctChart",
 | 
			
		||||
                    "implementation": MCTChart,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$interval",
 | 
			
		||||
                        "$log"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "controllers": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "PlotController",
 | 
			
		||||
                    "implementation": PlotController,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$scope",
 | 
			
		||||
                        "$element",
 | 
			
		||||
                        "exportImageService",
 | 
			
		||||
                        "telemetryFormatter",
 | 
			
		||||
                        "telemetryHandler",
 | 
			
		||||
                        "throttle",
 | 
			
		||||
                        "PLOT_FIXED_DURATION",
 | 
			
		||||
                        "openmct"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "PlotOptionsController",
 | 
			
		||||
                    "implementation": PlotOptionsController,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$scope"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "services": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "exportImageService",
 | 
			
		||||
                    "implementation": exportImageService,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$q",
 | 
			
		||||
                        "$timeout",
 | 
			
		||||
                        "$log",
 | 
			
		||||
                        "EXPORT_IMAGE_TIMEOUT"
 | 
			
		||||
                    ]
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "constants": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "PLOT_FIXED_DURATION",
 | 
			
		||||
                    "value": 900000,
 | 
			
		||||
                    "priority": "fallback",
 | 
			
		||||
                    "comment": "Fifteen minutes."
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "EXPORT_IMAGE_TIMEOUT",
 | 
			
		||||
                    "value": 500,
 | 
			
		||||
                    "priority": "fallback"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "policies": [
 | 
			
		||||
                {
 | 
			
		||||
                    "category": "view",
 | 
			
		||||
                    "implementation": PlotViewPolicy,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "openmct"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "representations": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "plot-options-browse",
 | 
			
		||||
                    "template": plotOptionsBrowseTemplate
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "licenses": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "FileSaver.js",
 | 
			
		||||
                    "version": "0.0.2",
 | 
			
		||||
                    "author": "Eli Grey",
 | 
			
		||||
                    "description": "File download initiator (for file exports)",
 | 
			
		||||
                    "website": "https://github.com/eligrey/FileSaver.js/",
 | 
			
		||||
                    "copyright": "Copyright © 2015 Eli Grey.",
 | 
			
		||||
                    "license": "license-mit",
 | 
			
		||||
                    "link": "https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "html2canvas",
 | 
			
		||||
                    "version": "0.4.1",
 | 
			
		||||
                    "author": "Niklas von Hertzen",
 | 
			
		||||
                    "description": "JavaScript HTML renderer",
 | 
			
		||||
                    "website": "https://github.com/niklasvh/html2canvas",
 | 
			
		||||
                    "copyright": "Copyright © 2012 Niklas von Hertzen.",
 | 
			
		||||
                    "license": "license-mit",
 | 
			
		||||
                    "link": "https://github.com/niklasvh/html2canvas/blob/master/LICENSE"
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,70 @@
 | 
			
		||||
<!--
 | 
			
		||||
 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 ng-controller="PlotOptionsController" class="flex-elem grows l-inspector-part">
 | 
			
		||||
    <em class="t-inspector-part-header" title="Display properties for this object">Plot Options</em>
 | 
			
		||||
    <mct-form
 | 
			
		||||
            ng-model="configuration.plot.xAxis"
 | 
			
		||||
            structure="xAxisForm"
 | 
			
		||||
            name="xAxisFormState"
 | 
			
		||||
            class="flex-elem l-flex-row no-margin">
 | 
			
		||||
    </mct-form>
 | 
			
		||||
    <mct-form
 | 
			
		||||
            ng-model="configuration.plot.yAxis"
 | 
			
		||||
            structure="yAxisForm"
 | 
			
		||||
            name="yAxisFormState"
 | 
			
		||||
            class="flex-elem l-flex-row no-margin">
 | 
			
		||||
    </mct-form>
 | 
			
		||||
    <div class="form">
 | 
			
		||||
        <div class="section-header ng-binding ng-scope">
 | 
			
		||||
            Plot Series
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul class="first flex-elem grows vscroll">
 | 
			
		||||
            <ul class="tree">
 | 
			
		||||
                <li ng-repeat="child in children">
 | 
			
		||||
                    <span ng-controller="ToggleController as toggle">
 | 
			
		||||
                        <span ng-controller="TreeNodeController as treeNode">
 | 
			
		||||
                            <span class="tree-item menus-to-left">
 | 
			
		||||
                                <span
 | 
			
		||||
                                    class='ui-symbol view-control flex-elem has-children'
 | 
			
		||||
                                    ng-class="{ expanded: toggle.isActive() }"
 | 
			
		||||
                                    ng-click="toggle.toggle(); treeNode.trackExpansion()">
 | 
			
		||||
                                </span>
 | 
			
		||||
                                <mct-representation
 | 
			
		||||
                                    class="rep-object-label"
 | 
			
		||||
                                    key="'label'"
 | 
			
		||||
                                    mct-object="child">
 | 
			
		||||
                                </mct-representation>
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </span>
 | 
			
		||||
                        <mct-form
 | 
			
		||||
                            ng-class="{hidden: !toggle.isActive()}"
 | 
			
		||||
                            ng-model="configuration.plot.series[$index]"
 | 
			
		||||
                            structure="plotSeriesForm"
 | 
			
		||||
                            name="plotOptionsState"
 | 
			
		||||
                            class="flex-elem l-flex-row">
 | 
			
		||||
                        </mct-form>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										165
									
								
								platform/features/plot/res/templates/plot.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								platform/features/plot/res/templates/plot.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
			
		||||
<!--
 | 
			
		||||
 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.
 | 
			
		||||
-->
 | 
			
		||||
<span ng-controller="PlotController as plot"
 | 
			
		||||
      class="abs holder holder-plot has-control-bar">
 | 
			
		||||
    <div class="l-control-bar" ng-show="!plot.hideExportButtons">
 | 
			
		||||
         <span class="l-btn-set">
 | 
			
		||||
            <a class="s-button t-export labeled icon-download"
 | 
			
		||||
               ng-click="plot.exportPNG()"
 | 
			
		||||
               title="Export This View's Data as PNG">
 | 
			
		||||
                PNG
 | 
			
		||||
            </a>
 | 
			
		||||
            <a class="s-button t-export labeled"
 | 
			
		||||
               ng-click="plot.exportJPG()"
 | 
			
		||||
               title="Export This View's Data as JPG">
 | 
			
		||||
                JPG
 | 
			
		||||
            </a>
 | 
			
		||||
        </span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="l-view-section">
 | 
			
		||||
        <div class="gl-plot"
 | 
			
		||||
             ng-style="{ height: 100 / plot.getSubPlots().length + '%'}"
 | 
			
		||||
             ng-repeat="subplot in plot.getSubPlots()">
 | 
			
		||||
            <div class="gl-plot-legend">
 | 
			
		||||
                <span class='plot-legend-item'
 | 
			
		||||
                        ng-repeat="telemetryObject in subplot.getTelemetryObjects()"
 | 
			
		||||
                        ng-class="plot.getLegendClass(telemetryObject)">
 | 
			
		||||
                    <span class='plot-color-swatch'
 | 
			
		||||
                          ng-style="{ 'background-color': plot.getColor($index) }">
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span class='title-label'>{{telemetryObject.getModel().name}}</span>
 | 
			
		||||
                </span>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-axis-area gl-plot-y">
 | 
			
		||||
                <div class="gl-plot-label gl-plot-y-label">
 | 
			
		||||
                    {{axes[1].active.name}}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div ng-repeat="tick in subplot.getRangeTicks()"
 | 
			
		||||
                     class="gl-plot-tick gl-plot-y-tick-label"
 | 
			
		||||
                     ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%' }">
 | 
			
		||||
                    {{tick.label | reverse}}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="gl-plot-y-options gl-plot-local-controls"
 | 
			
		||||
                     ng-if="axes[1].options.length > 1">
 | 
			
		||||
                    <div class='form-control shell select'>
 | 
			
		||||
                        <select class="form-control input shell"
 | 
			
		||||
                                ng-model="axes[1].active"
 | 
			
		||||
                                ng-options="option.name for option in axes[1].options">
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-wrapper-display-area-and-x-axis">
 | 
			
		||||
                <mct-include key="'time-of-interest'"
 | 
			
		||||
                             class="l-toi-holder show-val"
 | 
			
		||||
                             ng-if="toiPerc"
 | 
			
		||||
                             ng-class="{ 'pinned': toiPinned, 'val-to-left': toiPerc > 80 }"
 | 
			
		||||
                             ng-style="{'left': toiPerc + '%'}"></mct-include>
 | 
			
		||||
 | 
			
		||||
                <div class="gl-plot-coords"
 | 
			
		||||
                     ng-if="subplot.isHovering() && subplot.getHoverCoordinates()">
 | 
			
		||||
                    {{subplot.getHoverCoordinates()}}
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="gl-plot-display-area"
 | 
			
		||||
                     ng-mouseenter="subplot.isHovering(true);"
 | 
			
		||||
                     ng-mouseleave="subplot.isHovering(false)"
 | 
			
		||||
                     ng-class="{ loading: plot.isRequestPending() }">
 | 
			
		||||
 | 
			
		||||
                    <!-- Out-of-bounds data indicators -->
 | 
			
		||||
                    <!-- ng-show is temporarily hard-coded in next element -->
 | 
			
		||||
                    <div ng-show="false" class="l-oob-data l-oob-data-up"></div>
 | 
			
		||||
                    <div ng-show="false" class="l-oob-data l-oob-data-dwn"></div>
 | 
			
		||||
                    <div class="gl-plot-hash hash-v"
 | 
			
		||||
                         ng-repeat="tick in subplot.getDomainTicks()"
 | 
			
		||||
                         ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%', height: '100%' }"
 | 
			
		||||
                         ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="gl-plot-hash hash-h"
 | 
			
		||||
                         ng-repeat="tick in subplot.getRangeTicks()"
 | 
			
		||||
                         ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%', width: '100%' }"
 | 
			
		||||
                         ng-show="$index > 0 && $index < (subplot.getRangeTicks().length - 1)">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <mct-chart draw="subplot.getDrawingObject()"
 | 
			
		||||
                               ng-if="subplot.getTelemetryObjects().length > 0"
 | 
			
		||||
                               ng-mousemove="subplot.hover($event)"
 | 
			
		||||
                               mct-drag="subplot.continueDrag($event)"
 | 
			
		||||
                               mct-drag-down="subplot.startDrag($event)"
 | 
			
		||||
                               mct-drag-up="subplot.endDrag($event); plot.update()">
 | 
			
		||||
                    </mct-chart>
 | 
			
		||||
                    <!-- TODO: Move into correct position; make part of group; infer from set of actions -->
 | 
			
		||||
                    <div class="l-local-controls gl-plot-local-controls t-plot-display-controls"
 | 
			
		||||
                         ng-if="$first">
 | 
			
		||||
                        <a class="s-button icon-arrow-left"
 | 
			
		||||
                           ng-click="plot.stepBackPanZoom()"
 | 
			
		||||
                           ng-show="plot.isZoomed()"
 | 
			
		||||
                           title="Restore previous pan/zoom">
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <a class="s-button icon-arrows-out"
 | 
			
		||||
                           ng-click="plot.unzoom()"
 | 
			
		||||
                           ng-show="plot.isZoomed()"
 | 
			
		||||
                           title="Reset pan/zoom">
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <div class="menu-element s-menu-button menus-to-left {{plot.getMode().cssClass}}"
 | 
			
		||||
                             ng-if="plot.getModeOptions().length > 1"
 | 
			
		||||
                             ng-controller="ClickAwayController as toggle">
 | 
			
		||||
                            <span class="l-click-area" ng-click="toggle.toggle()"></span>
 | 
			
		||||
                            <span>{{plot.getMode().name}}</span>
 | 
			
		||||
                            <div class="menu" ng-show="toggle.isActive()">
 | 
			
		||||
                                <ul>
 | 
			
		||||
                                    <li ng-repeat="option in plot.getModeOptions()"
 | 
			
		||||
                                        ng-click="plot.setMode(option); toggle.setState(false)"
 | 
			
		||||
                                        class="{{option.cssClass}}">
 | 
			
		||||
                                        {{option.name}}
 | 
			
		||||
                                    </li>
 | 
			
		||||
                                </ul>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div ng-if="$last" class="gl-plot-axis-area gl-plot-x">
 | 
			
		||||
                    <div ng-repeat="tick in subplot.getDomainTicks()"
 | 
			
		||||
                         class="gl-plot-tick gl-plot-x-tick-label"
 | 
			
		||||
                         ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)"
 | 
			
		||||
                         ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%' }">
 | 
			
		||||
                        {{tick.label | reverse}}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="gl-plot-label gl-plot-x-label">
 | 
			
		||||
                        {{axes[0].active.name}}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="gl-plot-x-options gl-plot-local-controls"
 | 
			
		||||
                         ng-if="axes[0].options.length > 1">
 | 
			
		||||
                        <div class='form-control shell select'>
 | 
			
		||||
                            <select class="form-control input shell"
 | 
			
		||||
                                    ng-model="axes[0].active"
 | 
			
		||||
                                    ng-options="option.name for option in axes[0].options">
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</span>
 | 
			
		||||
							
								
								
									
										117
									
								
								platform/features/plot/src/Canvas2DChart.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								platform/features/plot/src/Canvas2DChart.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Create a new chart which uses Canvas's 2D API for rendering.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @implements {platform/features/plot.Chart}
 | 
			
		||||
         * @param {CanvasElement} canvas the canvas object to render upon
 | 
			
		||||
         * @throws {Error} an error is thrown if Canvas's 2D API is unavailable.
 | 
			
		||||
         */
 | 
			
		||||
        function Canvas2DChart(canvas) {
 | 
			
		||||
            this.canvas = canvas;
 | 
			
		||||
            this.c2d = canvas.getContext('2d');
 | 
			
		||||
            this.width = canvas.width;
 | 
			
		||||
            this.height = canvas.height;
 | 
			
		||||
            this.dimensions = [this.width, this.height];
 | 
			
		||||
            this.origin = [0, 0];
 | 
			
		||||
 | 
			
		||||
            if (!this.c2d) {
 | 
			
		||||
                throw new Error("Canvas 2d API unavailable.");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Convert from logical to physical x coordinates
 | 
			
		||||
        Canvas2DChart.prototype.x = function (v) {
 | 
			
		||||
            return ((v - this.origin[0]) / this.dimensions[0]) * this.width;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Convert from logical to physical y coordinates
 | 
			
		||||
        Canvas2DChart.prototype.y = function (v) {
 | 
			
		||||
            return this.height -
 | 
			
		||||
                ((v - this.origin[1]) / this.dimensions[1]) * this.height;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Set the color to be used for drawing operations
 | 
			
		||||
        Canvas2DChart.prototype.setColor = function (color) {
 | 
			
		||||
            var mappedColor = color.map(function (c, i) {
 | 
			
		||||
                return i < 3 ? Math.floor(c * 255) : (c);
 | 
			
		||||
            }).join(',');
 | 
			
		||||
            this.c2d.strokeStyle = "rgba(" + mappedColor + ")";
 | 
			
		||||
            this.c2d.fillStyle = "rgba(" + mappedColor + ")";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.clear = function () {
 | 
			
		||||
            var canvas = this.canvas;
 | 
			
		||||
            this.width = canvas.width;
 | 
			
		||||
            this.height = canvas.height;
 | 
			
		||||
            this.c2d.clearRect(0, 0, this.width, this.height);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.setDimensions = function (newDimensions, newOrigin) {
 | 
			
		||||
            this.dimensions = newDimensions;
 | 
			
		||||
            this.origin = newOrigin;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.drawLine = function (buf, color, points) {
 | 
			
		||||
            var i;
 | 
			
		||||
 | 
			
		||||
            this.setColor(color);
 | 
			
		||||
 | 
			
		||||
            // Configure context to draw two-pixel-thick lines
 | 
			
		||||
            this.c2d.lineWidth = 2;
 | 
			
		||||
 | 
			
		||||
            // Start a new path...
 | 
			
		||||
            if (buf.length > 1) {
 | 
			
		||||
                this.c2d.beginPath();
 | 
			
		||||
                this.c2d.moveTo(this.x(buf[0]), this.y(buf[1]));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // ...and add points to it...
 | 
			
		||||
            for (i = 2; i < points * 2; i = i + 2) {
 | 
			
		||||
                this.c2d.lineTo(this.x(buf[i]), this.y(buf[i + 1]));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // ...before finally drawing it.
 | 
			
		||||
            this.c2d.stroke();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.drawSquare = function (min, max, color) {
 | 
			
		||||
            var x1 = this.x(min[0]),
 | 
			
		||||
                y1 = this.y(min[1]),
 | 
			
		||||
                w = this.x(max[0]) - x1,
 | 
			
		||||
                h = this.y(max[1]) - y1;
 | 
			
		||||
 | 
			
		||||
            this.setColor(color);
 | 
			
		||||
            this.c2d.fillRect(x1, y1, w, h);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return Canvas2DChart;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										160
									
								
								platform/features/plot/src/GLChart.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								platform/features/plot/src/GLChart.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 GLPlot. Created by vwoeltje on 11/12/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        // WebGL shader sources (for drawing plain colors)
 | 
			
		||||
        var FRAGMENT_SHADER = [
 | 
			
		||||
                "precision mediump float;",
 | 
			
		||||
                "uniform vec4 uColor;",
 | 
			
		||||
                "void main(void) {",
 | 
			
		||||
                "gl_FragColor = uColor;",
 | 
			
		||||
                "}"
 | 
			
		||||
            ].join('\n'),
 | 
			
		||||
            VERTEX_SHADER = [
 | 
			
		||||
                "attribute vec2 aVertexPosition;",
 | 
			
		||||
                "uniform vec2 uDimensions;",
 | 
			
		||||
                "uniform vec2 uOrigin;",
 | 
			
		||||
                "void main(void) {",
 | 
			
		||||
                "gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);",
 | 
			
		||||
                "}"
 | 
			
		||||
            ].join('\n');
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Create a new chart which uses WebGL for rendering.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @implements {platform/features/plot.Chart}
 | 
			
		||||
         * @param {CanvasElement} canvas the canvas object to render upon
 | 
			
		||||
         * @throws {Error} an error is thrown if WebGL is unavailable.
 | 
			
		||||
         */
 | 
			
		||||
        function GLChart(canvas) {
 | 
			
		||||
            var gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }) ||
 | 
			
		||||
                    canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true }),
 | 
			
		||||
                vertexShader,
 | 
			
		||||
                fragmentShader,
 | 
			
		||||
                program,
 | 
			
		||||
                aVertexPosition,
 | 
			
		||||
                uColor,
 | 
			
		||||
                uDimensions,
 | 
			
		||||
                uOrigin;
 | 
			
		||||
 | 
			
		||||
            // Ensure a context was actually available before proceeding
 | 
			
		||||
            if (!gl) {
 | 
			
		||||
                throw new Error("WebGL unavailable.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Initialize shaders
 | 
			
		||||
            vertexShader = gl.createShader(gl.VERTEX_SHADER);
 | 
			
		||||
            gl.shaderSource(vertexShader, VERTEX_SHADER);
 | 
			
		||||
            gl.compileShader(vertexShader);
 | 
			
		||||
            fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
 | 
			
		||||
            gl.shaderSource(fragmentShader, FRAGMENT_SHADER);
 | 
			
		||||
            gl.compileShader(fragmentShader);
 | 
			
		||||
 | 
			
		||||
            // Assemble vertex/fragment shaders into programs
 | 
			
		||||
            program = gl.createProgram();
 | 
			
		||||
            gl.attachShader(program, vertexShader);
 | 
			
		||||
            gl.attachShader(program, fragmentShader);
 | 
			
		||||
            gl.linkProgram(program);
 | 
			
		||||
            gl.useProgram(program);
 | 
			
		||||
 | 
			
		||||
            // Get locations for attribs/uniforms from the
 | 
			
		||||
            // shader programs (to pass values into shaders at draw-time)
 | 
			
		||||
            aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
 | 
			
		||||
            uColor = gl.getUniformLocation(program, "uColor");
 | 
			
		||||
            uDimensions = gl.getUniformLocation(program, "uDimensions");
 | 
			
		||||
            uOrigin = gl.getUniformLocation(program, "uOrigin");
 | 
			
		||||
            gl.enableVertexAttribArray(aVertexPosition);
 | 
			
		||||
 | 
			
		||||
            // Create a buffer to holds points which will be drawn
 | 
			
		||||
            this.buffer = gl.createBuffer();
 | 
			
		||||
 | 
			
		||||
            // Use a line width of 2.0 for legibility
 | 
			
		||||
            gl.lineWidth(2.0);
 | 
			
		||||
 | 
			
		||||
            // Enable blending, for smoothness
 | 
			
		||||
            gl.enable(gl.BLEND);
 | 
			
		||||
            gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
 | 
			
		||||
 | 
			
		||||
            this.gl = gl;
 | 
			
		||||
            this.aVertexPosition = aVertexPosition;
 | 
			
		||||
            this.uColor = uColor;
 | 
			
		||||
            this.uDimensions = uDimensions;
 | 
			
		||||
            this.uOrigin = uOrigin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Utility function to handle drawing of a buffer;
 | 
			
		||||
        // drawType will determine whether this is a box, line, etc.
 | 
			
		||||
        GLChart.prototype.doDraw = function (drawType, buf, color, points) {
 | 
			
		||||
            var gl = this.gl;
 | 
			
		||||
            gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
 | 
			
		||||
            gl.bufferData(gl.ARRAY_BUFFER, buf, gl.DYNAMIC_DRAW);
 | 
			
		||||
            gl.vertexAttribPointer(this.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
 | 
			
		||||
            gl.uniform4fv(this.uColor, color);
 | 
			
		||||
            gl.drawArrays(drawType, 0, points);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.clear = function () {
 | 
			
		||||
            var gl = this.gl;
 | 
			
		||||
 | 
			
		||||
            // Set the viewport size; note that we use the width/height
 | 
			
		||||
            // that our WebGL context reports, which may be lower
 | 
			
		||||
            // resolution than the canvas we requested.
 | 
			
		||||
            gl.viewport(
 | 
			
		||||
                0,
 | 
			
		||||
                0,
 | 
			
		||||
                gl.drawingBufferWidth,
 | 
			
		||||
                gl.drawingBufferHeight
 | 
			
		||||
            );
 | 
			
		||||
            gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.setDimensions = function (dimensions, origin) {
 | 
			
		||||
            var gl = this.gl;
 | 
			
		||||
            if (dimensions && dimensions.length > 0 &&
 | 
			
		||||
                origin && origin.length > 0) {
 | 
			
		||||
                gl.uniform2fv(this.uDimensions, dimensions);
 | 
			
		||||
                gl.uniform2fv(this.uOrigin, origin);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.drawLine = function (buf, color, points) {
 | 
			
		||||
            this.doDraw(this.gl.LINE_STRIP, buf, color, points);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.drawSquare = function (min, max, color) {
 | 
			
		||||
            this.doDraw(this.gl.TRIANGLE_FAN, new Float32Array(
 | 
			
		||||
                min.concat([min[0], max[1]]).concat(max).concat([max[0], min[1]])
 | 
			
		||||
            ), color, 4);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return GLChart;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										250
									
								
								platform/features/plot/src/MCTChart.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								platform/features/plot/src/MCTChart.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,250 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 MCTChart. Created by vwoeltje on 11/12/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["./GLChart", "./Canvas2DChart"],
 | 
			
		||||
    function (GLChart, Canvas2DChart) {
 | 
			
		||||
 | 
			
		||||
        var TEMPLATE = "<canvas style='position: absolute; background: none; width: 100%; height: 100%;'></canvas>";
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The mct-chart directive provides a canvas element which can be
 | 
			
		||||
         * drawn upon, to support Plot view and similar visualizations.
 | 
			
		||||
         *
 | 
			
		||||
         * This directive takes one attribute, "draw", which is an Angular
 | 
			
		||||
         * expression which will be two-way bound to a drawing object. This
 | 
			
		||||
         * drawing object should contain:
 | 
			
		||||
         *
 | 
			
		||||
         * * `dimensions`: An object describing the logical bounds of the
 | 
			
		||||
         *   drawable area, containing two fields:
 | 
			
		||||
         *   * `origin`: The position, in logical coordinates, of the
 | 
			
		||||
         *     lower-left corner of the chart area. A two-element array.
 | 
			
		||||
         *   * `dimensions`: A two-element array containing the width
 | 
			
		||||
         *     and height of the chart area, in logical coordinates.
 | 
			
		||||
         * * `lines`: An array of lines to be drawn, where each line is
 | 
			
		||||
         *   expressed as an object containing:
 | 
			
		||||
         *   * `buffer`: A Float32Array containing points in the line,
 | 
			
		||||
         *     in logical coordinate, in sequential x/y pairs.
 | 
			
		||||
         *   * `color`: The color of the line, as a four-element RGBA
 | 
			
		||||
         *     array, where each element is in the range of 0.0-1.0
 | 
			
		||||
         *   * `points`: The number of points in the line.
 | 
			
		||||
         * * `boxes`: An array of rectangles to draw in the chart area
 | 
			
		||||
         *   (used for marquee zoom). Each is an object containing:
 | 
			
		||||
         *   * `start`: The first corner of the rectangle (as a two-element
 | 
			
		||||
         *      array, logical coordinates)
 | 
			
		||||
         *   * `end`: The opposite corner of the rectangle (again, as a
 | 
			
		||||
         *      two-element array)
 | 
			
		||||
         *   * `color`: The color of the box, as a four-element RGBA
 | 
			
		||||
         *     array, where each element is in the range of 0.0-1.0
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function MCTChart($interval, $log) {
 | 
			
		||||
            // Get an underlying chart implementation
 | 
			
		||||
            function getChart(Charts, canvas) {
 | 
			
		||||
                // Try the first available option...
 | 
			
		||||
                var Chart = Charts[0];
 | 
			
		||||
 | 
			
		||||
                // This function recursively try-catches all options;
 | 
			
		||||
                // if these all fail, issue a warning.
 | 
			
		||||
                if (!Chart) {
 | 
			
		||||
                    $log.warn("Cannot initialize mct-chart.");
 | 
			
		||||
                    return undefined;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Try first option; if it fails, try remaining options
 | 
			
		||||
                try {
 | 
			
		||||
                    return new Chart(canvas);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    $log.warn([
 | 
			
		||||
                        "Could not instantiate chart",
 | 
			
		||||
                        Chart.name,
 | 
			
		||||
                        ";",
 | 
			
		||||
                        e.message
 | 
			
		||||
                    ].join(" "));
 | 
			
		||||
 | 
			
		||||
                    return getChart(Charts.slice(1), canvas);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function linkChart(scope, element) {
 | 
			
		||||
                var canvas = element.find("canvas")[0],
 | 
			
		||||
                    activeInterval,
 | 
			
		||||
                    chart;
 | 
			
		||||
 | 
			
		||||
                // Handle drawing, based on contents of the "draw" object
 | 
			
		||||
                // in scope
 | 
			
		||||
                function doDraw(draw) {
 | 
			
		||||
                    // Ensure canvas context has same resolution
 | 
			
		||||
                    // as canvas element
 | 
			
		||||
                    canvas.width = canvas.offsetWidth;
 | 
			
		||||
                    canvas.height = canvas.offsetHeight;
 | 
			
		||||
 | 
			
		||||
                    // Clear previous contents
 | 
			
		||||
                    chart.clear();
 | 
			
		||||
 | 
			
		||||
                    // Nothing to draw if no draw object defined
 | 
			
		||||
                    if (!draw) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Set logical boundaries for the chart
 | 
			
		||||
                    chart.setDimensions(
 | 
			
		||||
                        draw.dimensions || [1, 1],
 | 
			
		||||
                        draw.origin || [0, 0]
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    // Draw line segments
 | 
			
		||||
                    (draw.lines || []).forEach(function (line) {
 | 
			
		||||
                        chart.drawLine(
 | 
			
		||||
                            line.buffer,
 | 
			
		||||
                            line.color,
 | 
			
		||||
                            line.points
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    // Draw boxes (e.g. marquee zoom rect)
 | 
			
		||||
                    (draw.boxes || []).forEach(function (box) {
 | 
			
		||||
                        chart.drawSquare(
 | 
			
		||||
                            box.start,
 | 
			
		||||
                            box.end,
 | 
			
		||||
                            box.color
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Issue a drawing call, if-and-only-if canvas size
 | 
			
		||||
                // has changed. This will be called on a timer, since
 | 
			
		||||
                // there is no event to depend on.
 | 
			
		||||
                function drawIfResized() {
 | 
			
		||||
                    if (canvas.width !== canvas.offsetWidth ||
 | 
			
		||||
                            canvas.height !== canvas.offsetHeight) {
 | 
			
		||||
                        doDraw(scope.draw);
 | 
			
		||||
                        scope.$apply();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Stop watching for changes to size (scope destroyed)
 | 
			
		||||
                function releaseInterval() {
 | 
			
		||||
                    if (activeInterval) {
 | 
			
		||||
                        $interval.cancel(activeInterval);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Switch from WebGL to plain 2D if context is lost
 | 
			
		||||
                function fallbackFromWebGL() {
 | 
			
		||||
                    element.html(TEMPLATE);
 | 
			
		||||
                    canvas = element.find("canvas")[0];
 | 
			
		||||
                    chart = getChart([Canvas2DChart], canvas);
 | 
			
		||||
                    if (chart) {
 | 
			
		||||
                        doDraw(scope.draw);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Try to initialize a chart.
 | 
			
		||||
                chart = getChart([GLChart, Canvas2DChart], canvas);
 | 
			
		||||
 | 
			
		||||
                // If that failed, there's nothing more we can do here.
 | 
			
		||||
                // (A warning will already have been issued)
 | 
			
		||||
                if (!chart) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // WebGL is a bit of a special case; it may work, then fail
 | 
			
		||||
                // later for various reasons, so we need to listen for this
 | 
			
		||||
                // and fall back to plain canvas drawing when it occurs.
 | 
			
		||||
                canvas.addEventListener("webglcontextlost", fallbackFromWebGL);
 | 
			
		||||
 | 
			
		||||
                // Check for resize, on a timer
 | 
			
		||||
                activeInterval = $interval(drawIfResized, 1000, 0, false);
 | 
			
		||||
 | 
			
		||||
                // Watch "draw" for external changes to the set of
 | 
			
		||||
                // things to be drawn.
 | 
			
		||||
                scope.$watchCollection("draw", doDraw);
 | 
			
		||||
 | 
			
		||||
                // Stop checking for resize when scope is destroyed
 | 
			
		||||
                scope.$on("$destroy", releaseInterval);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                // Apply directive only to elements
 | 
			
		||||
                restrict: "E",
 | 
			
		||||
 | 
			
		||||
                // Template to use (a canvas element)
 | 
			
		||||
                template: TEMPLATE,
 | 
			
		||||
 | 
			
		||||
                // Link function; set up scope
 | 
			
		||||
                link: linkChart,
 | 
			
		||||
 | 
			
		||||
                // Initial, isolate scope for the directive
 | 
			
		||||
                scope: { draw: "=" }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * @interface platform/features/plot.Chart
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Clear the chart.
 | 
			
		||||
         * @method platform/features/plot.Chart#clear
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the logical boundaries of the chart.
 | 
			
		||||
         * @param {number[]} dimensions the horizontal and
 | 
			
		||||
         *        vertical dimensions of the chart
 | 
			
		||||
         * @param {number[]} origin the horizontal/vertical
 | 
			
		||||
         *        origin of the chart
 | 
			
		||||
         * @memberof platform/features/plot.Chart#setDimensions
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * Draw the supplied buffer as a line strip (a sequence
 | 
			
		||||
         * of line segments), in the chosen color.
 | 
			
		||||
         * @param {Float32Array} buf the line strip to draw,
 | 
			
		||||
         *        in alternating x/y positions
 | 
			
		||||
         * @param {number[]} color the color to use when drawing
 | 
			
		||||
         *        the line, as an RGBA color where each element
 | 
			
		||||
         *        is in the range of 0.0-1.0
 | 
			
		||||
         * @param {number} points the number of points to draw
 | 
			
		||||
         * @memberof platform/features/plot.Chart#drawLine
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * Draw a rectangle extending from one corner to another,
 | 
			
		||||
         * in the chosen color.
 | 
			
		||||
         * @param {number[]} min the first corner of the rectangle
 | 
			
		||||
         * @param {number[]} max the opposite corner
 | 
			
		||||
         * @param {number[]} color the color to use when drawing
 | 
			
		||||
         *        the rectangle, as an RGBA color where each element
 | 
			
		||||
         *        is in the range of 0.0-1.0
 | 
			
		||||
         * @memberof platform/features/plot.Chart#drawSquare
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        return MCTChart;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										437
									
								
								platform/features/plot/src/PlotController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								platform/features/plot/src/PlotController.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,437 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 adds a "Plot" view for numeric telemetry data.
 | 
			
		||||
 * @namespace platform/features/plot
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        "./elements/PlotUpdater",
 | 
			
		||||
        "./elements/PlotPalette",
 | 
			
		||||
        "./elements/PlotAxis",
 | 
			
		||||
        "./elements/PlotLimitTracker",
 | 
			
		||||
        "./elements/PlotTelemetryFormatter",
 | 
			
		||||
        "./modes/PlotModeOptions",
 | 
			
		||||
        "./SubPlotFactory"
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        PlotUpdater,
 | 
			
		||||
        PlotPalette,
 | 
			
		||||
        PlotAxis,
 | 
			
		||||
        PlotLimitTracker,
 | 
			
		||||
        PlotTelemetryFormatter,
 | 
			
		||||
        PlotModeOptions,
 | 
			
		||||
        SubPlotFactory
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        var AXIS_DEFAULTS = [
 | 
			
		||||
                { "name": "Time" },
 | 
			
		||||
                { "name": "Value" }
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The PlotController is responsible for any computation/logic
 | 
			
		||||
         * associated with displaying the plot view. Specifically, these
 | 
			
		||||
         * responsibilities include:
 | 
			
		||||
         *
 | 
			
		||||
         * * Describing axes and labeling.
 | 
			
		||||
         * * Handling user interactions.
 | 
			
		||||
         * * Deciding what needs to be drawn in the chart area.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function PlotController(
 | 
			
		||||
            $scope,
 | 
			
		||||
            $element,
 | 
			
		||||
            exportImageService,
 | 
			
		||||
            telemetryFormatter,
 | 
			
		||||
            telemetryHandler,
 | 
			
		||||
            throttle,
 | 
			
		||||
            PLOT_FIXED_DURATION,
 | 
			
		||||
            openmct
 | 
			
		||||
        ) {
 | 
			
		||||
            var self = this,
 | 
			
		||||
                plotTelemetryFormatter =
 | 
			
		||||
                    new PlotTelemetryFormatter(telemetryFormatter),
 | 
			
		||||
                subPlotFactory =
 | 
			
		||||
                    new SubPlotFactory(plotTelemetryFormatter),
 | 
			
		||||
                cachedObjects = [],
 | 
			
		||||
                updater,
 | 
			
		||||
                lastBounds,
 | 
			
		||||
                lastRange,
 | 
			
		||||
                lastDomain,
 | 
			
		||||
                handle;
 | 
			
		||||
            var timeAPI = openmct.time;
 | 
			
		||||
 | 
			
		||||
            // Populate the scope with axis information (specifically, options
 | 
			
		||||
            // available for each axis.)
 | 
			
		||||
            function setupAxes(metadatas) {
 | 
			
		||||
                $scope.axes.forEach(function (axis) {
 | 
			
		||||
                    axis.updateMetadata(metadatas);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Trigger an update of a specific subplot;
 | 
			
		||||
            // used in a loop to update all subplots.
 | 
			
		||||
            function updateSubplot(subplot) {
 | 
			
		||||
                subplot.update();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Set up available modes (stacked/overlaid), based on the
 | 
			
		||||
            // set of telemetry objects in this plot view.
 | 
			
		||||
            function setupModes(telemetryObjects) {
 | 
			
		||||
                if (cachedObjects !== telemetryObjects) {
 | 
			
		||||
                    cachedObjects = telemetryObjects;
 | 
			
		||||
                    self.modeOptions = new PlotModeOptions(
 | 
			
		||||
                        telemetryObjects || [],
 | 
			
		||||
                        subPlotFactory
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Change the displayable bounds
 | 
			
		||||
            function setBasePanZoom(bounds) {
 | 
			
		||||
                var start = bounds.start,
 | 
			
		||||
                    end = bounds.end;
 | 
			
		||||
                if (updater) {
 | 
			
		||||
                    updater.setDomainBounds(start, end);
 | 
			
		||||
                    self.update();
 | 
			
		||||
                }
 | 
			
		||||
                lastBounds = bounds;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Reinstantiate the plot updater (e.g. because we have a
 | 
			
		||||
            // new subscription.) This will clear the plot.
 | 
			
		||||
            function recreateUpdater() {
 | 
			
		||||
                var domain = $scope.axes[0].active.key,
 | 
			
		||||
                    range = $scope.axes[1].active.key,
 | 
			
		||||
                    duration = PLOT_FIXED_DURATION;
 | 
			
		||||
 | 
			
		||||
                updater = new PlotUpdater(handle, domain, range, duration);
 | 
			
		||||
                lastDomain = domain;
 | 
			
		||||
                lastRange = range;
 | 
			
		||||
 | 
			
		||||
                self.limitTracker = new PlotLimitTracker(handle, range);
 | 
			
		||||
 | 
			
		||||
                // Keep any externally-provided bounds
 | 
			
		||||
                if (lastBounds) {
 | 
			
		||||
                    setBasePanZoom(lastBounds);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function getUpdater() {
 | 
			
		||||
                if (!updater) {
 | 
			
		||||
                    recreateUpdater();
 | 
			
		||||
                }
 | 
			
		||||
                return updater;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Handle new telemetry data in this plot
 | 
			
		||||
            function updateValues() {
 | 
			
		||||
                self.pending = false;
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    setupModes(handle.getTelemetryObjects());
 | 
			
		||||
                    setupAxes(handle.getMetadata());
 | 
			
		||||
                    getUpdater().update();
 | 
			
		||||
                    self.modeOptions.getModeHandler().plotTelemetry(updater);
 | 
			
		||||
                    self.limitTracker.update();
 | 
			
		||||
                    self.update();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Display new historical data as it becomes available
 | 
			
		||||
            function addHistoricalData(domainObject, series) {
 | 
			
		||||
                self.pending = false;
 | 
			
		||||
                getUpdater().addHistorical(domainObject, series);
 | 
			
		||||
                self.modeOptions.getModeHandler().plotTelemetry(updater);
 | 
			
		||||
                self.update();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Issue a new request for historical telemetry
 | 
			
		||||
            function requestTelemetry() {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    handle.request({}, addHistoricalData);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Requery for data entirely
 | 
			
		||||
            function replot() {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    updater = undefined;
 | 
			
		||||
                    requestTelemetry();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function changeTimeOfInterest(timeOfInterest) {
 | 
			
		||||
                if (timeOfInterest !== undefined) {
 | 
			
		||||
                    var bounds = timeAPI.bounds();
 | 
			
		||||
                    var range = bounds.end - bounds.start;
 | 
			
		||||
                    $scope.toiPerc = ((timeOfInterest - bounds.start) / range) * 100;
 | 
			
		||||
                    $scope.toiPinned = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    $scope.toiPerc = undefined;
 | 
			
		||||
                    $scope.toiPinned = false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Create a new subscription; telemetrySubscriber gets
 | 
			
		||||
            // to do the meaningful work here.
 | 
			
		||||
            function subscribe(domainObject) {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    handle.unsubscribe();
 | 
			
		||||
                }
 | 
			
		||||
                handle = domainObject && telemetryHandler.handle(
 | 
			
		||||
                    domainObject,
 | 
			
		||||
                    updateValues,
 | 
			
		||||
                    true // Lossless
 | 
			
		||||
                );
 | 
			
		||||
                replot();
 | 
			
		||||
 | 
			
		||||
                changeTimeOfInterest(timeAPI.timeOfInterest());
 | 
			
		||||
                timeAPI.on("timeOfInterest", changeTimeOfInterest);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Release the current subscription (called when scope is destroyed)
 | 
			
		||||
            function releaseSubscription() {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    handle.unsubscribe();
 | 
			
		||||
                    handle = undefined;
 | 
			
		||||
                }
 | 
			
		||||
                timeAPI.off("timeOfInterest", changeTimeOfInterest);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function requery() {
 | 
			
		||||
                self.pending = true;
 | 
			
		||||
                releaseSubscription();
 | 
			
		||||
                subscribe($scope.domainObject);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function updateDomainFormat() {
 | 
			
		||||
                var domainAxis = $scope.axes[0];
 | 
			
		||||
                plotTelemetryFormatter
 | 
			
		||||
                    .setDomainFormat(domainAxis.active.format);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function domainRequery(newDomain) {
 | 
			
		||||
                if (newDomain !== lastDomain) {
 | 
			
		||||
                    updateDomainFormat();
 | 
			
		||||
                    requery();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function rangeRequery(newRange) {
 | 
			
		||||
                if (newRange !== lastRange) {
 | 
			
		||||
                    requery();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Respond to a display bounds change (requery for data)
 | 
			
		||||
            function changeDisplayBounds(event, bounds, follow) {
 | 
			
		||||
                //'hack' for follow mode
 | 
			
		||||
                if (follow === true) {
 | 
			
		||||
                    setBasePanZoom(bounds);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var domainAxis = $scope.axes[0];
 | 
			
		||||
 | 
			
		||||
                    if (bounds.domain) {
 | 
			
		||||
                        domainAxis.chooseOption(bounds.domain);
 | 
			
		||||
                    }
 | 
			
		||||
                    updateDomainFormat();
 | 
			
		||||
                    setBasePanZoom(bounds);
 | 
			
		||||
                    requery();
 | 
			
		||||
                }
 | 
			
		||||
                self.setUnsynchedStatus($scope.domainObject, follow && self.isZoomed());
 | 
			
		||||
                changeTimeOfInterest(timeAPI.timeOfInterest());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.modeOptions = new PlotModeOptions([], subPlotFactory);
 | 
			
		||||
            this.updateValues = updateValues;
 | 
			
		||||
 | 
			
		||||
            // Create a throttled update function
 | 
			
		||||
            this.scheduleUpdate = throttle(function () {
 | 
			
		||||
                self.modeOptions.getModeHandler().getSubPlots()
 | 
			
		||||
                    .forEach(updateSubplot);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            self.pending = true;
 | 
			
		||||
            self.$element = $element;
 | 
			
		||||
            self.exportImageService = exportImageService;
 | 
			
		||||
 | 
			
		||||
            // Initialize axes; will get repopulated when telemetry
 | 
			
		||||
            // metadata becomes available.
 | 
			
		||||
            $scope.axes = [
 | 
			
		||||
                new PlotAxis("domains", [], AXIS_DEFAULTS[0]),
 | 
			
		||||
                new PlotAxis("ranges", [], AXIS_DEFAULTS[1])
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            //Are some initialized bounds defined?
 | 
			
		||||
            var bounds = timeAPI.bounds();
 | 
			
		||||
            if (bounds &&
 | 
			
		||||
                bounds.start !== undefined &&
 | 
			
		||||
                bounds.end !== undefined) {
 | 
			
		||||
                changeDisplayBounds(undefined, timeAPI.bounds(), timeAPI.clock() !== undefined);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Watch for changes to the selected axis
 | 
			
		||||
            $scope.$watch("axes[0].active.key", domainRequery);
 | 
			
		||||
            $scope.$watch("axes[1].active.key", rangeRequery);
 | 
			
		||||
 | 
			
		||||
            // Subscribe to telemetry when a domain object becomes available
 | 
			
		||||
            $scope.$watch('domainObject', subscribe);
 | 
			
		||||
 | 
			
		||||
            // Respond to external bounds changes
 | 
			
		||||
            $scope.$on("telemetry:display:bounds", changeDisplayBounds);
 | 
			
		||||
 | 
			
		||||
            // Unsubscribe when the plot is destroyed
 | 
			
		||||
            $scope.$on("$destroy", releaseSubscription);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the color (as a style-friendly string) to use
 | 
			
		||||
         * for plotting the trace at the specified index.
 | 
			
		||||
         * @param {number} index the index of the trace
 | 
			
		||||
         * @returns {string} the color, in #RRGGBB form
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getColor = function (index) {
 | 
			
		||||
            return PlotPalette.getStringColor(index);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Check if the plot is zoomed or panned out
 | 
			
		||||
         * of its default state (to determine whether back/unzoom
 | 
			
		||||
         * controls should be shown)
 | 
			
		||||
         * @returns {boolean} true if not in default state
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.isZoomed = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().isZoomed();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Undo the most recent pan/zoom change and restore
 | 
			
		||||
         * the prior state.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.stepBackPanZoom = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().stepBackPanZoom();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Undo all pan/zoom changes and restore the initial state.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.unzoom = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().unzoom();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the mode options (Stacked/Overlaid) that are applicable
 | 
			
		||||
         * for this plot.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getModeOptions = function () {
 | 
			
		||||
            return this.modeOptions.getModeOptions();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the current mode that is applicable to this plot. This
 | 
			
		||||
         * will include key, name, and cssClass fields.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getMode = function () {
 | 
			
		||||
            return this.modeOptions.getMode();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the mode which should be active in this plot.
 | 
			
		||||
         * @param mode one of the mode options returned from
 | 
			
		||||
         *        getModeOptions()
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.setMode = function (mode) {
 | 
			
		||||
            this.modeOptions.setMode(mode);
 | 
			
		||||
            this.updateValues();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get all individual plots contained within this Plot view.
 | 
			
		||||
         * (Multiple may be contained when in Stacked mode).
 | 
			
		||||
         * @returns {SubPlot[]} all subplots in this Plot view
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getSubPlots = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().getSubPlots();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the CSS class to apply to the legend for this domain
 | 
			
		||||
         * object; this will reflect limit state.
 | 
			
		||||
         * @returns {string} the CSS class
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getLegendClass = function (telemetryObject) {
 | 
			
		||||
            return this.limitTracker &&
 | 
			
		||||
                this.limitTracker.getLegendClass(telemetryObject);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Explicitly update all plots.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.update = function () {
 | 
			
		||||
            this.scheduleUpdate();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Check if a request is pending (to show the wait spinner)
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.isRequestPending = function () {
 | 
			
		||||
            // Placeholder; this should reflect request state
 | 
			
		||||
            // when requesting historical telemetry
 | 
			
		||||
            return this.pending;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotController.prototype.setUnsynchedStatus = function (domainObject, status) {
 | 
			
		||||
            if (domainObject.hasCapability('status')) {
 | 
			
		||||
                domainObject.getCapability('status').set('timeconductor-unsynced', status);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Export the plot to PNG
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.exportPNG = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            self.hideExportButtons = true;
 | 
			
		||||
            self.exportImageService.exportPNG(self.$element[0], "plot.png").finally(function () {
 | 
			
		||||
                self.hideExportButtons = false;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Export the plot to JPG
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.exportJPG = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            self.hideExportButtons = true;
 | 
			
		||||
            self.exportImageService.exportJPG(self.$element[0], "plot.jpg").finally(function () {
 | 
			
		||||
                self.hideExportButtons = false;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										195
									
								
								platform/features/plot/src/PlotOptionsController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								platform/features/plot/src/PlotOptionsController.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,195 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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(
 | 
			
		||||
    ['./PlotOptionsForm'],
 | 
			
		||||
    function (PlotOptionsForm) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Notes on implementation of plot options
 | 
			
		||||
         *
 | 
			
		||||
         * Multiple y-axes will have to be handled with multiple forms as
 | 
			
		||||
         * they will need to be stored on distinct model object
 | 
			
		||||
         *
 | 
			
		||||
         * Likewise plot series options per-child will need to be separate
 | 
			
		||||
         * forms.
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The LayoutController is responsible for supporting the
 | 
			
		||||
         * Layout view. It arranges frames according to saved configuration
 | 
			
		||||
         * and provides methods for updating these based on mouse
 | 
			
		||||
         * movement.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {Scope} $scope the controller's Angular scope
 | 
			
		||||
         */
 | 
			
		||||
        function PlotOptionsController($scope) {
 | 
			
		||||
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.$scope = $scope;
 | 
			
		||||
            this.domainObject = $scope.domainObject;
 | 
			
		||||
            this.configuration = this.domainObject.getModel().configuration || {};
 | 
			
		||||
            this.plotOptionsForm = new PlotOptionsForm();
 | 
			
		||||
            this.composition = [];
 | 
			
		||||
            this.watches = [];
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             Listen for changes to the domain object and update the object's
 | 
			
		||||
             children.
 | 
			
		||||
             */
 | 
			
		||||
            this.mutationListener = this.domainObject.getCapability('mutation').listen(function (model) {
 | 
			
		||||
                if (self.hasCompositionChanged(self.composition, model.composition)) {
 | 
			
		||||
                    self.updateChildren();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             Set form structures on scope
 | 
			
		||||
             */
 | 
			
		||||
            $scope.plotSeriesForm = this.plotOptionsForm.plotSeriesForm;
 | 
			
		||||
            $scope.xAxisForm = this.plotOptionsForm.xAxisForm;
 | 
			
		||||
            $scope.yAxisForm = this.plotOptionsForm.yAxisForm;
 | 
			
		||||
 | 
			
		||||
            $scope.$on("$destroy", function () {
 | 
			
		||||
                //Clean up any listeners on destruction of controller
 | 
			
		||||
                self.mutationListener();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.defaultConfiguration();
 | 
			
		||||
            this.updateChildren();
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             * Setup a number of watches for changes to form values. On
 | 
			
		||||
             * change, update the model configuration via mutation
 | 
			
		||||
             */
 | 
			
		||||
            $scope.$watchCollection('configuration.plot.yAxis', function (newValue, oldValue) {
 | 
			
		||||
                self.updateConfiguration(newValue, oldValue);
 | 
			
		||||
            });
 | 
			
		||||
            $scope.$watchCollection('configuration.plot.xAxis', function (newValue, oldValue) {
 | 
			
		||||
                self.updateConfiguration(newValue, oldValue);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.watchSeries();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Unregister all watches for series data (ie. the configuration for
 | 
			
		||||
         * child objects)
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.clearSeriesWatches = function () {
 | 
			
		||||
            this.watches.forEach(function (watch) {
 | 
			
		||||
                watch();
 | 
			
		||||
            });
 | 
			
		||||
            this.watches = [];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Attach watches for each object in the plot's composition
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.watchSeries = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
 | 
			
		||||
            this.clearSeriesWatches();
 | 
			
		||||
 | 
			
		||||
            (self.$scope.children || []).forEach(function (child, index) {
 | 
			
		||||
                self.watches.push(
 | 
			
		||||
                    self.$scope.$watchCollection(
 | 
			
		||||
                        'configuration.plot.series[' + index + ']',
 | 
			
		||||
                        function (newValue, oldValue) {
 | 
			
		||||
                            self.updateConfiguration(newValue, oldValue);
 | 
			
		||||
                        }
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Determine whether the changes to the model that triggered a
 | 
			
		||||
         * mutation event were purely compositional.
 | 
			
		||||
         *
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.hasCompositionChanged = function (oldComposition, newComposition) {
 | 
			
		||||
            // Framed slightly strangely, but the boolean logic is
 | 
			
		||||
            // easier to follow for the unchanged case.
 | 
			
		||||
            var isUnchanged = oldComposition === newComposition ||
 | 
			
		||||
                    (
 | 
			
		||||
                        oldComposition.length === newComposition.length &&
 | 
			
		||||
                        oldComposition.every(function (currentValue, index) {
 | 
			
		||||
                            return newComposition[index] && currentValue === newComposition[index];
 | 
			
		||||
                        })
 | 
			
		||||
                    );
 | 
			
		||||
            return !isUnchanged;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Default the plot options model
 | 
			
		||||
         *
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.defaultConfiguration = function () {
 | 
			
		||||
            this.configuration.plot = this.configuration.plot || {};
 | 
			
		||||
            this.configuration.plot.xAxis = this.configuration.plot.xAxis || {};
 | 
			
		||||
            this.configuration.plot.yAxis = this.configuration.plot.yAxis || {}; // y-axes will be associative array keyed on axis key
 | 
			
		||||
            this.configuration.plot.series = this.configuration.plot.series || []; // series will be associative array keyed on sub-object id
 | 
			
		||||
            this.$scope.configuration = this.configuration;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * When a child is added to, or removed from a plot, update the
 | 
			
		||||
         * plot options model
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.updateChildren = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.domainObject.useCapability('composition').then(function (children) {
 | 
			
		||||
                self.$scope.children = children;
 | 
			
		||||
                self.composition = self.domainObject.getModel().composition;
 | 
			
		||||
                children.forEach(function (child, index) {
 | 
			
		||||
                    self.configuration.plot.series[index] =
 | 
			
		||||
                        self.configuration.plot.series[index] || {'id': child.getId()};
 | 
			
		||||
                });
 | 
			
		||||
                self.watchSeries();
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * On changes to the form, update the configuration on the domain
 | 
			
		||||
         * object
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.updateConfiguration = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.domainObject.useCapability('mutation', function (model) {
 | 
			
		||||
                model.configuration = model.configuration || {};
 | 
			
		||||
                model.configuration.plot = self.configuration.plot;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotOptionsController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										150
									
								
								platform/features/plot/src/PlotOptionsForm.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								platform/features/plot/src/PlotOptionsForm.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A class for encapsulating structure and behaviour of the plot
 | 
			
		||||
         * options form
 | 
			
		||||
         * @memberOf platform/features/plot
 | 
			
		||||
         * @param topic
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function PlotOptionsForm() {
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             Defined below are the form structures for the plot options.
 | 
			
		||||
             */
 | 
			
		||||
            this.xAxisForm = {
 | 
			
		||||
                'name': 'x-axis',
 | 
			
		||||
                'sections': [{
 | 
			
		||||
                    'name': 'x-axis',
 | 
			
		||||
                    'rows': [
 | 
			
		||||
                        {
 | 
			
		||||
                            'name': 'Domain',
 | 
			
		||||
                            'control': 'select',
 | 
			
		||||
                            'key': 'key',
 | 
			
		||||
                            'options': [
 | 
			
		||||
                                {'name': 'SCET', 'value': 'scet'},
 | 
			
		||||
                                {'name': 'SCLK', 'value': 'sclk'},
 | 
			
		||||
                                {'name': 'LST', 'value': 'lst'}
 | 
			
		||||
                            ]
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }]};
 | 
			
		||||
 | 
			
		||||
            this.yAxisForm = {
 | 
			
		||||
                'name': 'y-axis',
 | 
			
		||||
                'sections': [{
 | 
			
		||||
                    // Will need to be repeated for each y-axis, with a
 | 
			
		||||
                    // distinct name for each. Ideally the name of the axis
 | 
			
		||||
                    // itself.
 | 
			
		||||
                    'name': 'y-axis',
 | 
			
		||||
                    'rows': [
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Range',
 | 
			
		||||
                        'control': 'select',
 | 
			
		||||
                        'key': 'key',
 | 
			
		||||
                        'options': [
 | 
			
		||||
                            {'name': 'EU', 'value': 'eu'},
 | 
			
		||||
                            {'name': 'DN', 'value': 'dn'},
 | 
			
		||||
                            {'name': 'Status', 'value': 'status'}
 | 
			
		||||
                        ]
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Autoscale',
 | 
			
		||||
                        'control': 'checkbox',
 | 
			
		||||
                        'key': 'autoscale'
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Min',
 | 
			
		||||
                        'control': 'textfield',
 | 
			
		||||
                        'key': 'min',
 | 
			
		||||
                        'pattern': '[0-9]',
 | 
			
		||||
                        'inputsize' : 'sm'
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Max',
 | 
			
		||||
                        'control': 'textfield',
 | 
			
		||||
                        'key': 'max',
 | 
			
		||||
                        'pattern': '[0-9]',
 | 
			
		||||
                        'inputsize' : 'sm'
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
                }]
 | 
			
		||||
            };
 | 
			
		||||
            this.plotSeriesForm = {
 | 
			
		||||
                'name': 'Series Options',
 | 
			
		||||
                'sections': [
 | 
			
		||||
                    {
 | 
			
		||||
                        rows: [
 | 
			
		||||
                        {
 | 
			
		||||
                            'name': 'Color',
 | 
			
		||||
                            'control': 'color',
 | 
			
		||||
                            'key': 'color'
 | 
			
		||||
                        }]
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'rows': [
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'Markers',
 | 
			
		||||
                                'control': 'checkbox',
 | 
			
		||||
                                'key': 'markers',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'rows': [
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'No Line',
 | 
			
		||||
                                'control': 'radio',
 | 
			
		||||
                                'key': 'lineType',
 | 
			
		||||
                                'value': 'noLine',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'Step Line',
 | 
			
		||||
                                'control': 'radio',
 | 
			
		||||
                                'key': 'lineType',
 | 
			
		||||
                                'value': 'stepLine',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'Linear Line',
 | 
			
		||||
                                'control': 'radio',
 | 
			
		||||
                                'key': 'lineType',
 | 
			
		||||
                                'value': 'linearLine',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return PlotOptionsForm;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user