Compare commits
	
		
			82 Commits
		
	
	
		
			slideshow
			...
			summary-wi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					28a3ada6af | ||
| 
						 | 
					ce0f24c86f | ||
| 
						 | 
					6ca2a755dc | ||
| 
						 | 
					f6c1488ccd | ||
| 
						 | 
					26be1ecf37 | ||
| 
						 | 
					38f0f072bb | ||
| 
						 | 
					e5e969665f | ||
| 
						 | 
					ffbb662c99 | ||
| 
						 | 
					bd7b23f896 | ||
| 
						 | 
					c238def902 | ||
| 
						 | 
					2d430ece7f | ||
| 
						 | 
					c92644a661 | ||
| 
						 | 
					41ce3c04f7 | ||
| 
						 | 
					fcf77f359f | ||
| 
						 | 
					40a2737915 | ||
| 
						 | 
					216489d67f | ||
| 
						 | 
					418a393b26 | ||
| 
						 | 
					1f3d744494 | ||
| 
						 | 
					ff3f2dccba | ||
| 
						 | 
					e69973bd29 | ||
| 
						 | 
					05b352cc36 | ||
| 
						 | 
					9735548999 | ||
| 
						 | 
					f9529b1362 | ||
| 
						 | 
					c598cec702 | ||
| 
						 | 
					e9ea1c4a0f | ||
| 
						 | 
					e9238ff282 | ||
| 
						 | 
					4cebd72cba | ||
| 
						 | 
					f8a44d6e71 | ||
| 
						 | 
					d0745b300b | ||
| 
						 | 
					2a4e0a3081 | ||
| 
						 | 
					1ff19f9574 | ||
| 
						 | 
					7ef84cb50d | ||
| 
						 | 
					cd05c70d64 | ||
| 
						 | 
					568473b82f | ||
| 
						 | 
					c61b074755 | ||
| 
						 | 
					8ed66ab4ab | ||
| 
						 | 
					b2502dd998 | ||
| 
						 | 
					856eedbf9d | ||
| 
						 | 
					0c0ca6e6af | ||
| 
						 | 
					498b797e49 | ||
| 
						 | 
					02c33388ba | ||
| 
						 | 
					8a8e3cc055 | ||
| 
						 | 
					36d60b16e9 | ||
| 
						 | 
					de3114568b | ||
| 
						 | 
					eb5835faeb | ||
| 
						 | 
					ff1ddb0b79 | ||
| 
						 | 
					15b127bb2e | ||
| 
						 | 
					e4ed881f6d | ||
| 
						 | 
					7b62cf130c | ||
| 
						 | 
					72fd2e531c | ||
| 
						 | 
					4a5392ef78 | ||
| 
						 | 
					0150a708ca | ||
| 
						 | 
					eacc181d5e | ||
| 
						 | 
					405bb55881 | ||
| 
						 | 
					4a35508459 | ||
| 
						 | 
					98a9d71a2e | ||
| 
						 | 
					a1596d0b06 | ||
| 
						 | 
					4b3be4c483 | ||
| 
						 | 
					0fa8472db1 | ||
| 
						 | 
					e1e2dca1d8 | ||
| 
						 | 
					755c013ec8 | ||
| 
						 | 
					eab702b763 | ||
| 
						 | 
					d15446ac91 | ||
| 
						 | 
					500733afb2 | ||
| 
						 | 
					2aa04b0a56 | ||
| 
						 | 
					c051f342af | ||
| 
						 | 
					8aeb365f5f | ||
| 
						 | 
					827a28313d | ||
| 
						 | 
					c83de8aad2 | ||
| 
						 | 
					b55f43b8df | ||
| 
						 | 
					8466723a90 | ||
| 
						 | 
					a103b4dbff | ||
| 
						 | 
					826ac3a947 | ||
| 
						 | 
					597327f138 | ||
| 
						 | 
					bef79402ca | ||
| 
						 | 
					e68e0c381f | ||
| 
						 | 
					c73f7259c2 | ||
| 
						 | 
					4c9235ba10 | ||
| 
						 | 
					55e2a77df8 | ||
| 
						 | 
					cfbff02e7f | ||
| 
						 | 
					54980fb296 | ||
| 
						 | 
					ba98d9315c | 
							
								
								
									
										2
									
								
								API.md
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								API.md
									
									
									
									
									
								
							@@ -505,7 +505,7 @@ MCT, it will be pre-configured to use the UTC time system, which is installed an
 | 
			
		||||
 | 
			
		||||
The time bounds of an Open MCT application are defined as numbers, and a Time 
 | 
			
		||||
System gives meaning and context to these numbers so that they can be correctly 
 | 
			
		||||
interpreted. Time Systems are JavaScript objects that provide some information 
 | 
			
		||||
interpreted. Time Systems are javscript objects that provide some information 
 | 
			
		||||
about the current time reference frame. An example of defining and registering 
 | 
			
		||||
a new time system is given below:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@
 | 
			
		||||
    "node-uuid": "^1.4.7",
 | 
			
		||||
    "comma-separated-values": "^3.6.4",
 | 
			
		||||
    "FileSaver.js": "^0.0.2",
 | 
			
		||||
    "zepto": "^1.1.6",
 | 
			
		||||
    "zepto": "1.2.0",
 | 
			
		||||
    "eventemitter3": "^1.2.0",
 | 
			
		||||
    "lodash": "3.10.1",
 | 
			
		||||
    "almond": "~0.3.2",
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ define([
 | 
			
		||||
            if (domainObject.telemetry && domainObject.telemetry.hasOwnProperty(prop)) {
 | 
			
		||||
                workerRequest[prop] = domainObject.telemetry[prop];
 | 
			
		||||
            }
 | 
			
		||||
            if (request.hasOwnProperty(prop)) {
 | 
			
		||||
            if (request && request.hasOwnProperty(prop)) {
 | 
			
		||||
                workerRequest[prop] = request[prop];
 | 
			
		||||
            }
 | 
			
		||||
            if (!workerRequest[prop]) {
 | 
			
		||||
@@ -78,8 +78,8 @@ define([
 | 
			
		||||
        return this.workerInterface.request(workerRequest);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    GeneratorProvider.prototype.subscribe = function (domainObject, callback) {
 | 
			
		||||
        var workerRequest = this.makeWorkerRequest(domainObject, {});
 | 
			
		||||
    GeneratorProvider.prototype.subscribe = function (domainObject, callback, request) {
 | 
			
		||||
        var workerRequest = this.makeWorkerRequest(domainObject, request);
 | 
			
		||||
        return this.workerInterface.subscribe(workerRequest, callback);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ define([
 | 
			
		||||
                { "key": "styleguide.intro", "name": "Introduction", "cssClass": "icon-page", "description": "Introduction and overview to the style guide" },
 | 
			
		||||
                { "key": "styleguide.standards", "name": "Standards", "cssClass": "icon-page", "description": "" },
 | 
			
		||||
                { "key": "styleguide.colors", "name": "Colors", "cssClass": "icon-page", "description": "" },
 | 
			
		||||
                { "key": "styleguide.status", "name": "status", "cssClass": "icon-page", "description": "Limits, telemetry paused, etc." },
 | 
			
		||||
                { "key": "styleguide.glyphs", "name": "Glyphs", "cssClass": "icon-page", "description": "Glyphs overview" },
 | 
			
		||||
                { "key": "styleguide.controls", "name": "Controls", "cssClass": "icon-page", "description": "Buttons, selects, HTML controls" },
 | 
			
		||||
                { "key": "styleguide.input", "name": "Text Inputs", "cssClass": "icon-page", "description": "Various text inputs" },
 | 
			
		||||
@@ -26,7 +25,6 @@ define([
 | 
			
		||||
                { "key": "styleguide.intro", "type": "styleguide.intro", "templateUrl": "templates/intro.html", "editable": false },
 | 
			
		||||
                { "key": "styleguide.standards", "type": "styleguide.standards", "templateUrl": "templates/standards.html", "editable": false },
 | 
			
		||||
                { "key": "styleguide.colors", "type": "styleguide.colors", "templateUrl": "templates/colors.html", "editable": false },
 | 
			
		||||
                { "key": "styleguide.status", "type": "styleguide.status", "templateUrl": "templates/status.html", "editable": false },
 | 
			
		||||
                { "key": "styleguide.glyphs", "type": "styleguide.glyphs", "templateUrl": "templates/glyphs.html", "editable": false },
 | 
			
		||||
                { "key": "styleguide.controls", "type": "styleguide.controls", "templateUrl": "templates/controls.html", "editable": false },
 | 
			
		||||
                { "key": "styleguide.input", "type": "styleguide.input", "templateUrl": "templates/input.html", "editable": false },
 | 
			
		||||
@@ -49,7 +47,6 @@ define([
 | 
			
		||||
                            "intro",
 | 
			
		||||
                            "standards",
 | 
			
		||||
                            "colors",
 | 
			
		||||
                            "status",
 | 
			
		||||
                            "glyphs",
 | 
			
		||||
                            "styleguide:ui-elements"
 | 
			
		||||
                        ]
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@
 | 
			
		||||
        color: $colorKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    h1, h2, strong, b {
 | 
			
		||||
        color: pullForward($colorBodyFg, 50%);
 | 
			
		||||
    h1, h2 {
 | 
			
		||||
        color: pullForward($colorBodyFg, 20%);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    h2 {
 | 
			
		||||
@@ -45,10 +45,6 @@
 | 
			
		||||
        text-transform: uppercase;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strong, b {
 | 
			
		||||
        font-weight: normal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .w-markup {
 | 
			
		||||
        //Wrap markup example "pre" element
 | 
			
		||||
        background-color: $colorCode;
 | 
			
		||||
@@ -58,12 +54,6 @@
 | 
			
		||||
        position: relative;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .w-mct-example {
 | 
			
		||||
        div {
 | 
			
		||||
            margin-bottom: $interiorMarginLg;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    code,
 | 
			
		||||
    pre {
 | 
			
		||||
        font-size: 0.8rem;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,5 +4,5 @@
 | 
			
		||||
        <pre></pre>
 | 
			
		||||
    </span>
 | 
			
		||||
    <h3>Example</h3>
 | 
			
		||||
    <div class="w-mct-example"></div>
 | 
			
		||||
    <div></div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -121,7 +121,7 @@
 | 
			
		||||
        <h2>Palettes</h2>
 | 
			
		||||
        <div class="cols cols1-1">
 | 
			
		||||
            <div class="col">
 | 
			
		||||
                <p>Use a palette to provide color choices. Similar to context menus and dropdowns, palettes should be dismissed when a choice is made within them, or if the user clicks outside one.</p>
 | 
			
		||||
                <p>Use a palette to provide color choices. Similar to context menus and dropdowns, palettes should be dismissed when a choice is made within them, or if the user clicks outside one. Selected palette choices should utilize the <code>selected</code> CSS class to visualize indicate that state.</p>
 | 
			
		||||
                <p>Note that while this example uses static markup for illustrative purposes, don't do this - use a front-end framework with repeaters to build the color choices.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <mct-example><div style="height: 220px" title="Ignore me, I'm just here to provide space for this example.">
 | 
			
		||||
@@ -129,9 +129,9 @@
 | 
			
		||||
<div class="s-button s-menu-button menu-element t-color-palette icon-paint-bucket" ng-controller="ClickAwayController as toggle">
 | 
			
		||||
    <span class="l-click-area" ng-click="toggle.toggle()"></span>
 | 
			
		||||
    <span class="color-swatch" style="background: rgb(255, 0, 0);"></span>
 | 
			
		||||
    <div class="menu l-color-palette" ng-show="toggle.isActive()">
 | 
			
		||||
    <div class="menu l-palette l-color-palette" ng-show="toggle.isActive()">
 | 
			
		||||
        <div class="l-palette-row l-option-row">
 | 
			
		||||
            <div class="l-palette-item s-palette-item " ng-click="ngModel[field] = 'transparent'"></div>
 | 
			
		||||
            <div class="l-palette-item s-palette-item no-selection"></div>
 | 
			
		||||
            <span class="l-palette-item-label">None</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="l-palette-row">
 | 
			
		||||
@@ -147,7 +147,7 @@
 | 
			
		||||
            <div class="l-palette-item s-palette-item" style="background: rgb(255, 255, 255);"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="l-palette-row">
 | 
			
		||||
            <div class="l-palette-item s-palette-item" style="background: rgb(136, 32, 32);"></div>
 | 
			
		||||
            <div class="l-palette-item s-palette-item selected" style="background: rgb(255, 0, 0);"></div>
 | 
			
		||||
            <div class="l-palette-item s-palette-item" style="background: rgb(224, 64, 64);"></div>
 | 
			
		||||
            <div class="l-palette-item s-palette-item" style="background: rgb(240, 160, 72);"></div>
 | 
			
		||||
            <div class="l-palette-item s-palette-item" style="background: rgb(255, 248, 96);"></div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,142 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT, Copyright (c) 2014-2016, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<style>
 | 
			
		||||
    .w-mct-example div[class*="s-limit"],
 | 
			
		||||
    .w-mct-example div[class*="s-status"],
 | 
			
		||||
    .w-mct-example div[class*="s-unsynced"],
 | 
			
		||||
    .w-mct-example span[class*="s-limit"] {
 | 
			
		||||
        border-radius: 4px;
 | 
			
		||||
        padding: 3px 7px;
 | 
			
		||||
    }
 | 
			
		||||
    .w-mct-example table {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
<div class="l-style-guide s-text">
 | 
			
		||||
    <p class="doc-title">Open MCT Style Guide</p>
 | 
			
		||||
    <h1>Status Indication</h1>
 | 
			
		||||
 | 
			
		||||
    <div class="l-section">
 | 
			
		||||
        <h2>Overview</h2>
 | 
			
		||||
        <p>Many elements in Open MCT need to articulate a dynamic status; Open MCT provides the following styles and conventions to handle this:</p>
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li><strong>Limits</strong>: when telemetry values exceed minimum or maximum values, they can be violating limits. Limit styles include both color and iconography; color is used to indicate severity while icons are used to indicate direction, upper or lower.</li>
 | 
			
		||||
            <li><strong>Status</strong>: Open MCT also provides a number or built-in Status styles allowing telemetry or other displayed information to be visually classified by type. Common uses for these classes are to visually denote event records.</li>
 | 
			
		||||
            <li><strong>Synchronization</strong>: When the system is displaying real-time data, it is very important that displays clearly indicate when they are not doing so, such as when a plot if frozen while panning or zooming. Open MCT provides a style for this.</li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="l-section">
 | 
			
		||||
        <h2>Limits</h2>
 | 
			
		||||
        <div class="cols cols1-1">
 | 
			
		||||
            <div class="col">
 | 
			
		||||
                <p>Limit CSS classes can be applied to any block or inline element. Open MCT limit classes set color and optionally an icon, but don't effect other properties. Yellow and red limit classes can be used as is, or allow the application of any custom icon available in Open MCT's glyphs library. "Level" limit classes - upper and lower - always use an icon in addition to a color; Open MCT doesn't support level limits without color.</p>
 | 
			
		||||
                <ul>
 | 
			
		||||
                    <li>Color only</li>
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        <li><code>s-limit-yellow</code>: A yellow limit.</li>
 | 
			
		||||
                        <li><code>s-limit-red</code>: A red limit.</li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                    <li>Color and icon</li>
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        <li><code>s-limit-yellow-icon</code>: A yellow limit with icon.</li>
 | 
			
		||||
                        <li><code>s-limit-red-icon</code>: A red limit with icon.</li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                    <li>Upper and lower limit indicators. Must be used with a color limit class to be visible.</li>
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        <li><code>s-limit-upr</code>: Upper limit.
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li><code>s-limit-lwr</code>: Lower limit.
 | 
			
		||||
                        </li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
<mct-example><div class="s-limit-yellow">Yellow limit</div>
 | 
			
		||||
<div class="s-limit-red">Red limit</div>
 | 
			
		||||
<div class="s-limit-yellow-icon">Yellow limit with icon</div>
 | 
			
		||||
<div class="s-limit-red-icon">Red limit with icon</div>
 | 
			
		||||
<div class="s-limit-yellow s-limit-lwr">Lower yellow limit</div>
 | 
			
		||||
<div class="s-limit-red s-limit-upr">Upper red limit</div>
 | 
			
		||||
<div class="s-limit-red icon-bell">Red Limit with a custom icon</div>
 | 
			
		||||
<div>Some text with an <span class="s-limit-yellow-icon">inline element</span> showing a yellow limit.</div>
 | 
			
		||||
 | 
			
		||||
<!-- Limits applied in a table -->
 | 
			
		||||
<table>
 | 
			
		||||
    <tr class='header'><td>Name</td><td>Value 1</td><td>Value 2</td></tr>
 | 
			
		||||
    <tr><td>ENG_PWR 4991</td><td>7.023</td><td class="s-limit-yellow s-limit-upr">70.23</td></tr>
 | 
			
		||||
    <tr><td>ENG_PWR 4992</td><td>49.784</td><td class="s-limit-red s-limit-lwr">-121.22</td></tr>
 | 
			
		||||
    <tr><td>ENG_PWR 4993</td><td class="s-limit-yellow icon-bell">0.451</td><td>1.007</td></tr>
 | 
			
		||||
</table>
 | 
			
		||||
</mct-example>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="l-section">
 | 
			
		||||
        <h2>Status</h2>
 | 
			
		||||
        <div class="cols cols1-1">
 | 
			
		||||
            <div class="col">
 | 
			
		||||
                <p>Classes here can be applied to elements as needed.</p>
 | 
			
		||||
                <ul>
 | 
			
		||||
                    <li>Color only</li>
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        <li><code>s-status-warning-hi</code></li>
 | 
			
		||||
                        <li><code>s-status-warning-lo</code></li>
 | 
			
		||||
                        <li><code>s-status-diagnostic</code></li>
 | 
			
		||||
                        <li><code>s-status-info</code></li>
 | 
			
		||||
                        <li><code>s-status-ok</code></li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                    <li>Color and icon</li>
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        <li><code>s-status-warning-hi-icon</code></li>
 | 
			
		||||
                        <li><code>s-status-warning-lo-icon</code></li>
 | 
			
		||||
                        <li><code>s-status-diagnostic-icon</code></li>
 | 
			
		||||
                        <li><code>s-status-info-icon</code></li>
 | 
			
		||||
                        <li><code>s-status-ok-icon</code></li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
<mct-example><div class="s-status-warning-hi">WARNING HI</div>
 | 
			
		||||
<div class="s-status-warning-lo">WARNING LOW</div>
 | 
			
		||||
<div class="s-status-diagnostic">DIAGNOSTIC</div>
 | 
			
		||||
<div class="s-status-info">INFO</div>
 | 
			
		||||
<div class="s-status-ok">OK</div>
 | 
			
		||||
<div class="s-status-warning-hi-icon">WARNING HI with icon</div>
 | 
			
		||||
<div class="s-status-warning-lo-icon">WARNING LOW with icon</div>
 | 
			
		||||
<div class="s-status-diagnostic-icon">DIAGNOSTIC with icon</div>
 | 
			
		||||
<div class="s-status-info-icon">INFO with icon</div>
 | 
			
		||||
<div class="s-status-ok-icon">OK with icon</div>
 | 
			
		||||
<div class="s-status-warning-hi icon-gear">WARNING HI with custom icon</div>
 | 
			
		||||
</mct-example>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="l-section">
 | 
			
		||||
        <h2>Synchronization</h2>
 | 
			
		||||
        <div class="cols cols1-1">
 | 
			
		||||
            <div class="col">
 | 
			
		||||
                <p>When the system is operating in real-time streaming mode, it is important for views that display real-time data to clearly articulate when they are not, such as when a user zooms or pans a plot view, freezing that view. In that case, the CSS class <code>s-unsynced</code> should be applied to that view.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
<mct-example><div class="s-unsynced">This element is unsynced</div>
 | 
			
		||||
</mct-example>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -34,7 +34,6 @@ define(
 | 
			
		||||
            pages['standards'] = { name: "Standards", type: "styleguide.standards", location: "styleguide:home" };
 | 
			
		||||
            pages['colors'] = { name: "Colors", type: "styleguide.colors", location: "styleguide:home" };
 | 
			
		||||
            pages['glyphs'] = { name: "Glyphs", type: "styleguide.glyphs", location: "styleguide:home" };
 | 
			
		||||
            pages['status'] = { name: "Status Indication", type: "styleguide.status", location: "styleguide:home" };
 | 
			
		||||
            pages['controls'] = { name: "Controls", type: "styleguide.controls", location: "styleguide:ui-elements" };
 | 
			
		||||
            pages['input'] = { name: "Text Inputs", type: "styleguide.input", location: "styleguide:ui-elements" };
 | 
			
		||||
            pages['menus'] = { name: "Menus", type: "styleguide.menus", location: "styleguide:ui-elements" };
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								gulpfile.js
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								gulpfile.js
									
									
									
									
									
								
							@@ -46,22 +46,9 @@ var gulp = require('gulp'),
 | 
			
		||||
            name: 'bower_components/almond/almond.js',
 | 
			
		||||
            include: paths.main.replace('.js', ''),
 | 
			
		||||
            wrap: {
 | 
			
		||||
                start: (function () {
 | 
			
		||||
                    var buildVariables = {
 | 
			
		||||
                        version: project.version,
 | 
			
		||||
                        timestamp: moment.utc(Date.now()).format(),
 | 
			
		||||
                        revision: fs.existsSync('.git') ? git.long() : 'Unknown',
 | 
			
		||||
                        branch: fs.existsSync('.git') ? git.branch() : 'Unknown'
 | 
			
		||||
                    };
 | 
			
		||||
                    return fs.readFileSync("src/start.frag", 'utf-8')
 | 
			
		||||
                        .replace(/@@(\w+)/g, function (match, key) {
 | 
			
		||||
                            return buildVariables[key];
 | 
			
		||||
                        });;
 | 
			
		||||
                }()),
 | 
			
		||||
                startFile: "src/start.frag",
 | 
			
		||||
                endFile: "src/end.frag"
 | 
			
		||||
            },
 | 
			
		||||
            optimize: 'uglify2',
 | 
			
		||||
            uglify2: { output: { comments: /@preserve/ } },
 | 
			
		||||
            mainConfigFile: paths.main,
 | 
			
		||||
            wrapShim: true
 | 
			
		||||
        },
 | 
			
		||||
@@ -71,6 +58,14 @@ var gulp = require('gulp'),
 | 
			
		||||
        },
 | 
			
		||||
        sass: {
 | 
			
		||||
            sourceComments: true
 | 
			
		||||
        },
 | 
			
		||||
        replace: {
 | 
			
		||||
            variables: {
 | 
			
		||||
                version: project.version,
 | 
			
		||||
                timestamp: moment.utc(Date.now()).format(),
 | 
			
		||||
                revision: fs.existsSync('.git') ? git.long() : 'Unknown',
 | 
			
		||||
                branch: fs.existsSync('.git') ? git.branch() : 'Unknown'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -81,11 +76,16 @@ if (process.env.NODE_ENV === 'development') {
 | 
			
		||||
 | 
			
		||||
gulp.task('scripts', function () {
 | 
			
		||||
    var requirejsOptimize = require('gulp-requirejs-optimize');
 | 
			
		||||
    var replace = require('gulp-replace-task');
 | 
			
		||||
    var header = require('gulp-header');
 | 
			
		||||
    var comment = fs.readFileSync('src/about.frag');
 | 
			
		||||
 | 
			
		||||
    return gulp.src(paths.main)
 | 
			
		||||
        .pipe(sourcemaps.init())
 | 
			
		||||
        .pipe(requirejsOptimize(options.requirejsOptimize))
 | 
			
		||||
        .pipe(sourcemaps.write('.'))
 | 
			
		||||
        .pipe(replace(options.replace))
 | 
			
		||||
        .pipe(header(comment, options.replace.variables))
 | 
			
		||||
        .pipe(gulp.dest(paths.dist));
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,7 @@
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
 | 
			
		||||
    <title></title>
 | 
			
		||||
    <script src="bower_components/requirejs/require.js">
 | 
			
		||||
    </script>
 | 
			
		||||
    <script src="bower_components/requirejs/require.js"> </script>
 | 
			
		||||
    <script>
 | 
			
		||||
        var THIRTY_MINUTES = 30 * 60 * 1000;
 | 
			
		||||
 | 
			
		||||
@@ -43,7 +42,6 @@
 | 
			
		||||
            openmct.install(openmct.plugins.Generator());
 | 
			
		||||
            openmct.install(openmct.plugins.ExampleImagery());
 | 
			
		||||
            openmct.install(openmct.plugins.UTCTimeSystem());
 | 
			
		||||
            openmct.install(openmct.plugins.ImportExport());
 | 
			
		||||
            openmct.install(openmct.plugins.Conductor({
 | 
			
		||||
                menuOptions: [
 | 
			
		||||
                    {
 | 
			
		||||
@@ -65,6 +63,7 @@
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            }));
 | 
			
		||||
            openmct.install(openmct.plugins.SummaryWidget());
 | 
			
		||||
            openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
 | 
			
		||||
            openmct.time.timeSystem('utc');
 | 
			
		||||
            openmct.start();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								openmct.js
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								openmct.js
									
									
									
									
									
								
							@@ -19,7 +19,7 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global requirejs,BUILD_CONSTANTS*/
 | 
			
		||||
/*global requirejs*/
 | 
			
		||||
 | 
			
		||||
requirejs.config({
 | 
			
		||||
    "paths": {
 | 
			
		||||
@@ -91,17 +91,12 @@ requirejs.config({
 | 
			
		||||
define([
 | 
			
		||||
    './platform/framework/src/Main',
 | 
			
		||||
    './src/defaultRegistry',
 | 
			
		||||
    './src/MCT',
 | 
			
		||||
    './src/plugins/buildInfo/plugin'
 | 
			
		||||
], function (Main, defaultRegistry, MCT, buildInfo) {
 | 
			
		||||
    './src/MCT'
 | 
			
		||||
], function (Main, defaultRegistry, MCT) {
 | 
			
		||||
    var openmct = new MCT();
 | 
			
		||||
 | 
			
		||||
    openmct.legacyRegistry = defaultRegistry;
 | 
			
		||||
 | 
			
		||||
    if (typeof BUILD_CONSTANTS !== 'undefined') {
 | 
			
		||||
        openmct.install(buildInfo(BUILD_CONSTANTS));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    openmct.on('start', function () {
 | 
			
		||||
        return new Main().run(defaultRegistry);
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -22,10 +22,12 @@
 | 
			
		||||
    "git-rev-sync": "^1.4.0",
 | 
			
		||||
    "glob": ">= 3.0.0",
 | 
			
		||||
    "gulp": "^3.9.1",
 | 
			
		||||
    "gulp-header": "^1.8.8",
 | 
			
		||||
    "gulp-jscs": "^3.0.2",
 | 
			
		||||
    "gulp-jshint": "^2.0.0",
 | 
			
		||||
    "gulp-jshint-html-reporter": "^0.1.3",
 | 
			
		||||
    "gulp-rename": "^1.2.2",
 | 
			
		||||
    "gulp-replace-task": "^0.11.0",
 | 
			
		||||
    "gulp-requirejs-optimize": "^0.3.1",
 | 
			
		||||
    "gulp-sass": "^2.2.0",
 | 
			
		||||
    "gulp-sourcemaps": "^1.6.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,6 @@ define([
 | 
			
		||||
    "./src/InspectorPaneController",
 | 
			
		||||
    "./src/BrowseObjectController",
 | 
			
		||||
    "./src/MenuArrowController",
 | 
			
		||||
    "./src/ObjectHeaderController",
 | 
			
		||||
    "./src/navigation/NavigationService",
 | 
			
		||||
    "./src/navigation/NavigateAction",
 | 
			
		||||
    "./src/navigation/OrphanNavigationHandler",
 | 
			
		||||
@@ -37,7 +36,6 @@ define([
 | 
			
		||||
    "text!./res/templates/browse-object.html",
 | 
			
		||||
    "text!./res/templates/items/grid-item.html",
 | 
			
		||||
    "text!./res/templates/browse/object-header.html",
 | 
			
		||||
    "text!./res/templates/browse/object-header-frame.html",
 | 
			
		||||
    "text!./res/templates/menu-arrow.html",
 | 
			
		||||
    "text!./res/templates/back-arrow.html",
 | 
			
		||||
    "text!./res/templates/items/items.html",
 | 
			
		||||
@@ -50,7 +48,6 @@ define([
 | 
			
		||||
    InspectorPaneController,
 | 
			
		||||
    BrowseObjectController,
 | 
			
		||||
    MenuArrowController,
 | 
			
		||||
    ObjectHeaderController,
 | 
			
		||||
    NavigationService,
 | 
			
		||||
    NavigateAction,
 | 
			
		||||
    OrphanNavigationHandler,
 | 
			
		||||
@@ -61,7 +58,6 @@ define([
 | 
			
		||||
    browseObjectTemplate,
 | 
			
		||||
    gridItemTemplate,
 | 
			
		||||
    objectHeaderTemplate,
 | 
			
		||||
    objectHeaderFrameTemplate,
 | 
			
		||||
    menuArrowTemplate,
 | 
			
		||||
    backArrowTemplate,
 | 
			
		||||
    itemsTemplate,
 | 
			
		||||
@@ -144,13 +140,6 @@ define([
 | 
			
		||||
                        "$location",
 | 
			
		||||
                        "$attrs"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "ObjectHeaderController",
 | 
			
		||||
                    "implementation": ObjectHeaderController,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$scope"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "representations": [
 | 
			
		||||
@@ -184,13 +173,6 @@ define([
 | 
			
		||||
                        "type"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "object-header-frame",
 | 
			
		||||
                    "template": objectHeaderFrameTemplate,
 | 
			
		||||
                    "uses": [
 | 
			
		||||
                        "type"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "menu-arrow",
 | 
			
		||||
                    "template": menuArrowTemplate,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +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.
 | 
			
		||||
-->
 | 
			
		||||
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
 | 
			
		||||
<span class="l-elem-wrapper l-flex-row flex-elem grows" ng-controller="ObjectHeaderController as controller">
 | 
			
		||||
    <span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
 | 
			
		||||
    <span class='title-label flex-elem holder flex-can-shrink s-input-inline'>{{model.name}}</span>
 | 
			
		||||
    <span class='t-object-alert t-alert-unsynced flex-elem holder' title='This object is not currently displaying real-time data'></span>
 | 
			
		||||
    <mct-representation
 | 
			
		||||
        key="'menu-arrow'"
 | 
			
		||||
        mct-object='domainObject'
 | 
			
		||||
        class="flex-elem context-available-w"></mct-representation>
 | 
			
		||||
</span>
 | 
			
		||||
@@ -20,13 +20,9 @@
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
 | 
			
		||||
<span class="l-elem-wrapper l-flex-row flex-elem grows" ng-controller="ObjectHeaderController as controller">
 | 
			
		||||
<span class="l-elem-wrapper l-flex-row flex-elem grows">
 | 
			
		||||
    <span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
 | 
			
		||||
    <span contenteditable="true" 
 | 
			
		||||
		class='title-label flex-elem holder flex-can-shrink s-input-inline'
 | 
			
		||||
		ng-click="controller.edit()"
 | 
			
		||||
		ng-blur="controller.updateName($event)"
 | 
			
		||||
		ng-keypress="controller.updateName($event)">{{model.name}}</span>
 | 
			
		||||
    <span class='title-label flex-elem holder flex-can-shrink'>{{model.name}}</span>
 | 
			
		||||
    <span class='t-object-alert t-alert-unsynced flex-elem holder' title='This object is not currently displaying real-time data'></span>
 | 
			
		||||
    <mct-representation
 | 
			
		||||
        key="'menu-arrow'"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,75 +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 () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Controller to provide the ability to inline edit an object name.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @memberof platform/commonUI/browse
 | 
			
		||||
         */
 | 
			
		||||
        function ObjectHeaderController($scope) {
 | 
			
		||||
            this.$scope = $scope;
 | 
			
		||||
            $scope.editing = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Updates the object name on blur and enter keypress events.
 | 
			
		||||
         *
 | 
			
		||||
         * @param event the mouse event
 | 
			
		||||
         */
 | 
			
		||||
        ObjectHeaderController.prototype.updateName = function (event) {
 | 
			
		||||
            if (event && (event.type === 'blur' || event.which === 13)) {
 | 
			
		||||
                var name = event.currentTarget.innerHTML;
 | 
			
		||||
 | 
			
		||||
                if (name.length === 0) {
 | 
			
		||||
                    name = "Unnamed " + this.$scope.domainObject.getCapability("type").typeDef.name;
 | 
			
		||||
                    event.currentTarget.innerHTML = name;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (name !== this.$scope.domainObject.model.name) {
 | 
			
		||||
                    this.$scope.domainObject.getCapability('mutation').mutate(function (model) {
 | 
			
		||||
                        model.name = name;
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.$scope.editing = false;
 | 
			
		||||
 | 
			
		||||
                if (event.which === 13) {
 | 
			
		||||
                    event.currentTarget.blur();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Marks the status of the field as editing.
 | 
			
		||||
         */
 | 
			
		||||
        ObjectHeaderController.prototype.edit = function () {
 | 
			
		||||
            this.$scope.editing = true;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return ObjectHeaderController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,120 +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(
 | 
			
		||||
    ["../src/ObjectHeaderController"],
 | 
			
		||||
    function (ObjectHeaderController) {
 | 
			
		||||
 | 
			
		||||
        describe("The object header controller", function () {
 | 
			
		||||
            var mockScope,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockCapabilities,
 | 
			
		||||
                mockMutationCapability,
 | 
			
		||||
                mockTypeCapability,
 | 
			
		||||
                mockEvent,
 | 
			
		||||
                mockCurrentTarget,
 | 
			
		||||
                controller;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
 | 
			
		||||
                mockTypeCapability = {
 | 
			
		||||
                    typeDef: {
 | 
			
		||||
                        name: ""
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                mockCapabilities = {
 | 
			
		||||
                    mutation: mockMutationCapability,
 | 
			
		||||
                    type: mockTypeCapability
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "model"]);
 | 
			
		||||
                mockDomainObject.model = {name: "Test name"};
 | 
			
		||||
                mockDomainObject.getCapability.andCallFake(function (key) {
 | 
			
		||||
                    return mockCapabilities[key];
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mockScope = {
 | 
			
		||||
                    domainObject: mockDomainObject
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "innerHTML"]);
 | 
			
		||||
                mockCurrentTarget.blur.andReturn(mockCurrentTarget);
 | 
			
		||||
 | 
			
		||||
                mockEvent = {
 | 
			
		||||
                    which: {},
 | 
			
		||||
                    type: {},
 | 
			
		||||
                    currentTarget: mockCurrentTarget
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                controller = new ObjectHeaderController(mockScope);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("updates the model with new name on blur", function () {
 | 
			
		||||
                mockEvent.type = "blur";
 | 
			
		||||
                mockCurrentTarget.innerHTML = "New name";
 | 
			
		||||
                controller.updateName(mockEvent);
 | 
			
		||||
 | 
			
		||||
                expect(mockMutationCapability.mutate).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("updates the model with a default for blank names", function () {
 | 
			
		||||
                mockEvent.type = "blur";
 | 
			
		||||
                mockCurrentTarget.innerHTML = "";
 | 
			
		||||
                controller.updateName(mockEvent);
 | 
			
		||||
 | 
			
		||||
                expect(mockCurrentTarget.innerHTML.length).not.toEqual(0);
 | 
			
		||||
                expect(mockMutationCapability.mutate).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("does not update the model if the same name", function () {
 | 
			
		||||
                mockEvent.type = "blur";
 | 
			
		||||
                mockCurrentTarget.innerHTML = mockDomainObject.model.name;
 | 
			
		||||
                controller.updateName(mockEvent);
 | 
			
		||||
 | 
			
		||||
                expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("updates the model on enter keypress event only", function () {
 | 
			
		||||
                mockCurrentTarget.innerHTML = "New name";
 | 
			
		||||
                controller.updateName(mockEvent);
 | 
			
		||||
 | 
			
		||||
                expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                mockEvent.which = 13;
 | 
			
		||||
                controller.updateName(mockEvent);
 | 
			
		||||
 | 
			
		||||
                expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
 | 
			
		||||
 | 
			
		||||
                mockMutationCapability.mutate.mostRecentCall.args[0](mockDomainObject.model);
 | 
			
		||||
 | 
			
		||||
                expect(mockDomainObject.model.name).toBe("New name");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("blurs the field on enter key press", function () {
 | 
			
		||||
                mockEvent.which = 13;
 | 
			
		||||
                controller.updateName(mockEvent);
 | 
			
		||||
 | 
			
		||||
                expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
    <div class="s-menu-button major create-button" ng-click="createController.toggle()">
 | 
			
		||||
		<span class="title-label">Create</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="menu super-menu l-create-menu" ng-show="createController.isActive()">
 | 
			
		||||
    <div class="menu super-menu" ng-show="createController.isActive()">
 | 
			
		||||
        <mct-representation mct-object="domainObject" key="'create-menu'">
 | 
			
		||||
        </mct-representation>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,8 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div class="w-menu" ng-controller="CreateMenuController">
 | 
			
		||||
    <div class="col menu-items">
 | 
			
		||||
<div class="contents" ng-controller="CreateMenuController">
 | 
			
		||||
    <div class="pane left menu-items">
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li ng-repeat="createAction in createActions" ng-click="createAction.perform()">
 | 
			
		||||
                <a ng-mouseover="representation.activeMetadata = createAction.getMetadata()"
 | 
			
		||||
@@ -31,15 +31,13 @@
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col menu-item-description">
 | 
			
		||||
    <div class="pane right menu-item-description">
 | 
			
		||||
        <div class="desc-area icon {{ representation.activeMetadata.cssClass }}"></div>
 | 
			
		||||
        <div class="w-title-desc">
 | 
			
		||||
            <div class="desc-area title">
 | 
			
		||||
                {{representation.activeMetadata.name}}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="desc-area description">
 | 
			
		||||
                {{representation.activeMetadata.description}}
 | 
			
		||||
            </div>
 | 
			
		||||
        <div class="desc-area title">
 | 
			
		||||
            {{representation.activeMetadata.name}}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="desc-area description">
 | 
			
		||||
            {{representation.activeMetadata.description}}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
  "metadata": {
 | 
			
		||||
    "name": "openmct-symbols-16px",
 | 
			
		||||
    "lastOpened": 0,
 | 
			
		||||
    "created": 1505151140023
 | 
			
		||||
    "created": 1502487054429
 | 
			
		||||
  },
 | 
			
		||||
  "iconSets": [
 | 
			
		||||
    {
 | 
			
		||||
@@ -636,29 +636,13 @@
 | 
			
		||||
          "code": 921670,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 138,
 | 
			
		||||
          "id": 115,
 | 
			
		||||
          "name": "icon-import",
 | 
			
		||||
          "prevSize": 24,
 | 
			
		||||
          "code": 921671,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 136,
 | 
			
		||||
          "id": 116,
 | 
			
		||||
          "name": "icon-export",
 | 
			
		||||
          "prevSize": 24,
 | 
			
		||||
          "code": 921672,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 37,
 | 
			
		||||
          "prevSize": 24,
 | 
			
		||||
          "name": "icon-activity",
 | 
			
		||||
          "id": 32,
 | 
			
		||||
          "code": 921856,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 36,
 | 
			
		||||
@@ -666,7 +650,7 @@
 | 
			
		||||
          "name": "icon-activity-mode",
 | 
			
		||||
          "id": 31,
 | 
			
		||||
          "code": 921857,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 52,
 | 
			
		||||
@@ -674,7 +658,7 @@
 | 
			
		||||
          "name": "icon-autoflow-tabular",
 | 
			
		||||
          "id": 47,
 | 
			
		||||
          "code": 921858,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 55,
 | 
			
		||||
@@ -682,7 +666,7 @@
 | 
			
		||||
          "name": "icon-clock",
 | 
			
		||||
          "id": 50,
 | 
			
		||||
          "code": 921859,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 58,
 | 
			
		||||
@@ -690,7 +674,7 @@
 | 
			
		||||
          "name": "icon-database",
 | 
			
		||||
          "id": 53,
 | 
			
		||||
          "code": 921860,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 57,
 | 
			
		||||
@@ -698,7 +682,7 @@
 | 
			
		||||
          "name": "icon-database-query",
 | 
			
		||||
          "id": 52,
 | 
			
		||||
          "code": 921861,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 17,
 | 
			
		||||
@@ -706,7 +690,7 @@
 | 
			
		||||
          "name": "icon-dataset",
 | 
			
		||||
          "id": 12,
 | 
			
		||||
          "code": 921862,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 22,
 | 
			
		||||
@@ -714,7 +698,7 @@
 | 
			
		||||
          "name": "icon-datatable",
 | 
			
		||||
          "id": 17,
 | 
			
		||||
          "code": 921863,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 59,
 | 
			
		||||
@@ -722,7 +706,7 @@
 | 
			
		||||
          "name": "icon-dictionary",
 | 
			
		||||
          "id": 54,
 | 
			
		||||
          "code": 921864,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 62,
 | 
			
		||||
@@ -730,7 +714,7 @@
 | 
			
		||||
          "name": "icon-folder",
 | 
			
		||||
          "id": 57,
 | 
			
		||||
          "code": 921865,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 66,
 | 
			
		||||
@@ -738,7 +722,7 @@
 | 
			
		||||
          "name": "icon-image",
 | 
			
		||||
          "id": 61,
 | 
			
		||||
          "code": 921872,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 68,
 | 
			
		||||
@@ -746,7 +730,7 @@
 | 
			
		||||
          "name": "icon-layout",
 | 
			
		||||
          "id": 63,
 | 
			
		||||
          "code": 921873,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 77,
 | 
			
		||||
@@ -754,7 +738,7 @@
 | 
			
		||||
          "name": "icon-object",
 | 
			
		||||
          "id": 72,
 | 
			
		||||
          "code": 921874,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 78,
 | 
			
		||||
@@ -762,7 +746,7 @@
 | 
			
		||||
          "name": "icon-object-unknown",
 | 
			
		||||
          "id": 73,
 | 
			
		||||
          "code": 921875,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 79,
 | 
			
		||||
@@ -770,7 +754,7 @@
 | 
			
		||||
          "name": "icon-packet",
 | 
			
		||||
          "id": 74,
 | 
			
		||||
          "code": 921876,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 80,
 | 
			
		||||
@@ -778,7 +762,7 @@
 | 
			
		||||
          "name": "icon-page",
 | 
			
		||||
          "id": 75,
 | 
			
		||||
          "code": 921877,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 135,
 | 
			
		||||
@@ -786,7 +770,7 @@
 | 
			
		||||
          "name": "icon-plot-overlay",
 | 
			
		||||
          "prevSize": 24,
 | 
			
		||||
          "code": 921878,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 113,
 | 
			
		||||
@@ -794,7 +778,7 @@
 | 
			
		||||
          "name": "icon-plot-stacked",
 | 
			
		||||
          "prevSize": 24,
 | 
			
		||||
          "code": 921879,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 10,
 | 
			
		||||
@@ -802,7 +786,7 @@
 | 
			
		||||
          "name": "icon-session",
 | 
			
		||||
          "id": 5,
 | 
			
		||||
          "code": 921880,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 24,
 | 
			
		||||
@@ -810,7 +794,7 @@
 | 
			
		||||
          "name": "icon-tabular",
 | 
			
		||||
          "id": 19,
 | 
			
		||||
          "code": 921881,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 7,
 | 
			
		||||
@@ -818,7 +802,7 @@
 | 
			
		||||
          "name": "icon-tabular-lad",
 | 
			
		||||
          "id": 2,
 | 
			
		||||
          "code": 921888,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 6,
 | 
			
		||||
@@ -826,7 +810,7 @@
 | 
			
		||||
          "name": "icon-tabular-lad-set",
 | 
			
		||||
          "id": 1,
 | 
			
		||||
          "code": 921889,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 8,
 | 
			
		||||
@@ -834,7 +818,7 @@
 | 
			
		||||
          "name": "icon-tabular-realtime",
 | 
			
		||||
          "id": 3,
 | 
			
		||||
          "code": 921890,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 23,
 | 
			
		||||
@@ -842,7 +826,7 @@
 | 
			
		||||
          "name": "icon-tabular-scrolling",
 | 
			
		||||
          "id": 18,
 | 
			
		||||
          "code": 921891,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 112,
 | 
			
		||||
@@ -850,7 +834,7 @@
 | 
			
		||||
          "name": "icon-telemetry",
 | 
			
		||||
          "id": 86,
 | 
			
		||||
          "code": 921892,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 90,
 | 
			
		||||
@@ -858,7 +842,7 @@
 | 
			
		||||
          "name": "icon-telemetry-panel",
 | 
			
		||||
          "id": 85,
 | 
			
		||||
          "code": 921893,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 93,
 | 
			
		||||
@@ -866,7 +850,7 @@
 | 
			
		||||
          "name": "icon-timeline",
 | 
			
		||||
          "id": 88,
 | 
			
		||||
          "code": 921894,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 116,
 | 
			
		||||
@@ -874,7 +858,7 @@
 | 
			
		||||
          "name": "icon-timer-v1.5",
 | 
			
		||||
          "prevSize": 24,
 | 
			
		||||
          "code": 921895,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 11,
 | 
			
		||||
@@ -882,7 +866,7 @@
 | 
			
		||||
          "name": "icon-topic",
 | 
			
		||||
          "id": 6,
 | 
			
		||||
          "code": 921896,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 115,
 | 
			
		||||
@@ -890,7 +874,7 @@
 | 
			
		||||
          "name": "icon-box-with-dashed-lines",
 | 
			
		||||
          "id": 29,
 | 
			
		||||
          "code": 921897,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 126,
 | 
			
		||||
@@ -898,7 +882,7 @@
 | 
			
		||||
          "name": "icon-summary-widget",
 | 
			
		||||
          "prevSize": 24,
 | 
			
		||||
          "code": 921904,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "metadata": {
 | 
			
		||||
@@ -2699,52 +2683,6 @@
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "id": 115,
 | 
			
		||||
          "paths": [
 | 
			
		||||
            "M832 192.4v639.4c0 0.2-0.2 0.2-0.4 0.4h-319.6v192h320c105.6 0 192-86.4 192-192v-640.2c0-105.6-86.4-192-192-192h-320v192h319.6c0.2 0 0.4 0.2 0.4 0.4z",
 | 
			
		||||
            "M192 704v192l384-384-384-384v192h-192v384z"
 | 
			
		||||
          ],
 | 
			
		||||
          "attrs": [
 | 
			
		||||
            {},
 | 
			
		||||
            {}
 | 
			
		||||
          ],
 | 
			
		||||
          "grid": 16,
 | 
			
		||||
          "tags": [
 | 
			
		||||
            "icon-import"
 | 
			
		||||
          ],
 | 
			
		||||
          "isMulticolor": false,
 | 
			
		||||
          "isMulticolor2": false,
 | 
			
		||||
          "colorPermutations": {
 | 
			
		||||
            "1161751207457516161751": [
 | 
			
		||||
              {},
 | 
			
		||||
              {}
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "id": 116,
 | 
			
		||||
          "paths": [
 | 
			
		||||
            "M192 831.66v-639.32l0.34-0.34h319.66v-192h-320c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h320v-192h-319.66z",
 | 
			
		||||
            "M1024 512l-384-384v192h-192v384h192v192l384-384z"
 | 
			
		||||
          ],
 | 
			
		||||
          "attrs": [
 | 
			
		||||
            {},
 | 
			
		||||
            {}
 | 
			
		||||
          ],
 | 
			
		||||
          "isMulticolor": false,
 | 
			
		||||
          "isMulticolor2": false,
 | 
			
		||||
          "grid": 16,
 | 
			
		||||
          "tags": [
 | 
			
		||||
            "icon-export"
 | 
			
		||||
          ],
 | 
			
		||||
          "colorPermutations": {
 | 
			
		||||
            "1161751207457516161751": [
 | 
			
		||||
              {},
 | 
			
		||||
              {}
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "paths": [
 | 
			
		||||
            "M576 64h-256l320 320h-290.256c-44.264-76.516-126.99-128-221.744-128h-128v512h128c94.754 0 177.48-51.484 221.744-128h290.256l-320 320h256l448-448-448-448z"
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -85,8 +85,6 @@
 | 
			
		||||
<glyph unicode="󡁄" glyph-name="icon-grid-snap-no" d="M768 384h192v-64h-192v64zM256 384h192v-64h-192v64zM0 384h192v-64h-192v64zM640 448h-64v-64h-64v-64h64v-64h64v64h64v64h-64zM576 704h64v-192h-64v192zM576 960h64v-192h-64v192zM576 192h64v-192h-64v192z" />
 | 
			
		||||
<glyph unicode="󡁅" glyph-name="icon-frame-show" d="M0 896v-896h1024v896h-1024zM896 128h-768v640h768v-640zM192 704h384v-128h-384v128z" />
 | 
			
		||||
<glyph unicode="󡁆" glyph-name="icon-frame-hide" d="M128 770h420l104 128h-652v-802.4l128 157.4zM896 130h-420l-104-128h652v802.4l-128-157.4zM832 962l-832-1024h192l832 1024zM392 578l104 128h-304v-128z" />
 | 
			
		||||
<glyph unicode="󡁇" glyph-name="icon-import" d="M832 767.6v-639.4c0-0.2-0.2-0.2-0.4-0.4h-319.6v-192h320c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192h-320v-192h319.6c0.2 0 0.4-0.2 0.4-0.4zM192 256v-192l384 384-384 384v-192h-192v-384z" />
 | 
			
		||||
<glyph unicode="󡁈" glyph-name="icon-export" d="M192 128.34v639.32l0.34 0.34h319.66v192h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h320v192h-319.66zM1024 448l-384 384v-192h-192v-384h192v-192l384 384z" />
 | 
			
		||||
<glyph unicode="󡄀" glyph-name="icon-activity" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
 | 
			
		||||
<glyph unicode="󡄁" glyph-name="icon-activity-mode" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
 | 
			
		||||
<glyph unicode="󡄂" glyph-name="icon-autoflow-tabular" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 43 KiB  | 
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/********************************************* COLUMN LAYOUTS STYLES */
 | 
			
		||||
@mixin cols($totalCols, $span) {
 | 
			
		||||
/*@mixin cols($totalCols, $span) {
 | 
			
		||||
    $cw: 100% / $totalCols;
 | 
			
		||||
    min-width: (500px / $totalCols) * $span;
 | 
			
		||||
    @if ($totalCols != $span) {
 | 
			
		||||
@@ -89,7 +89,7 @@
 | 
			
		||||
        @include clearfix;
 | 
			
		||||
        padding: $interiorMargin 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
/********************************************* FLEX STYLES */
 | 
			
		||||
.l-flex-row,
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/************************** FEATURES */
 | 
			
		||||
$enableImageryThumbs: true; // Set to true if historical imagery thumbnails are supported
 | 
			
		||||
$enableImageryThumbs: false; // Set to true if historical imagery thumbnails are supported
 | 
			
		||||
 | 
			
		||||
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
 | 
			
		||||
$bodyMargin: 10px;
 | 
			
		||||
@@ -82,7 +82,7 @@ $tabularTdPadTB: 2px;
 | 
			
		||||
/*************** Imagery */
 | 
			
		||||
$imageMainControlBarH: 25px;
 | 
			
		||||
$imageThumbsD: 120px;
 | 
			
		||||
$imageThumbsWrapperH: 155px;
 | 
			
		||||
$imageThumbsWrapperH: $imageThumbsD * 1.4;
 | 
			
		||||
$imageThumbPad: 1px;
 | 
			
		||||
/*************** Ticks */
 | 
			
		||||
$ticksH: 25px;
 | 
			
		||||
@@ -111,9 +111,7 @@ $bubbleMaxW: 300px;
 | 
			
		||||
$reqSymbolW: 15px;
 | 
			
		||||
$reqSymbolM: $interiorMargin * 2;
 | 
			
		||||
$reqSymbolFontSize: 0.75em;
 | 
			
		||||
$inputTextPTopBtm: 3px;
 | 
			
		||||
$inputTextPLeftRight: 5px;
 | 
			
		||||
$inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
 | 
			
		||||
$inputTextP: 3px 5px;
 | 
			
		||||
/*************** Wait Spinner Defaults */
 | 
			
		||||
$waitSpinnerD: 32px;
 | 
			
		||||
$waitSpinnerTreeD: 20px;
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,6 @@
 | 
			
		||||
			font-size: 0.8rem;
 | 
			
		||||
			$p: 1px;
 | 
			
		||||
			line-height: 100%;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
			&.l-static-text {
 | 
			
		||||
				padding: $p;
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -180,6 +180,20 @@ a.disabled {
 | 
			
		||||
    @include ellipsize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no-selection {
 | 
			
		||||
    // aka selection = "None". Used in palettes and their menu buttons.
 | 
			
		||||
    $c: red; $s: 48%; $e: 52%;
 | 
			
		||||
    @include background-image(linear-gradient(-45deg,
 | 
			
		||||
        transparent $s - 5%,
 | 
			
		||||
        $c $s,
 | 
			
		||||
        $c $e,
 | 
			
		||||
        transparent $e + 5%
 | 
			
		||||
    ));
 | 
			
		||||
    background-repeat: no-repeat;
 | 
			
		||||
    background-size: contain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.scrolling,
 | 
			
		||||
.scroll {
 | 
			
		||||
    overflow: auto;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,3 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
@mixin glyphBefore($unicode, $family: 'symbolsfont') {
 | 
			
		||||
    &:before {
 | 
			
		||||
        content: $unicode;
 | 
			
		||||
@@ -113,8 +92,6 @@ $glyph-icon-grid-snap-to: '\e1043';
 | 
			
		||||
$glyph-icon-grid-snap-no: '\e1044';
 | 
			
		||||
$glyph-icon-frame-show: '\e1045';
 | 
			
		||||
$glyph-icon-frame-hide: '\e1046';
 | 
			
		||||
$glyph-icon-import: '\e1047';
 | 
			
		||||
$glyph-icon-export: '\e1048';
 | 
			
		||||
$glyph-icon-activity: '\e1100';
 | 
			
		||||
$glyph-icon-activity-mode: '\e1101';
 | 
			
		||||
$glyph-icon-autoflow-tabular: '\e1102';
 | 
			
		||||
@@ -227,8 +204,6 @@ $glyph-icon-summary-widget: '\e1130';
 | 
			
		||||
.icon-grid-snap-no {  @include glyphBefore($glyph-icon-grid-snap-no); }
 | 
			
		||||
.icon-frame-show {  @include glyphBefore($glyph-icon-frame-show); }
 | 
			
		||||
.icon-frame-hide {  @include glyphBefore($glyph-icon-frame-hide); }
 | 
			
		||||
.icon-import {  @include glyphBefore($glyph-icon-import); }
 | 
			
		||||
.icon-export {  @include glyphBefore($glyph-icon-export); }
 | 
			
		||||
.icon-activity {  @include glyphBefore($glyph-icon-activity); }
 | 
			
		||||
.icon-activity-mode {  @include glyphBefore($glyph-icon-activity-mode); }
 | 
			
		||||
.icon-autoflow-tabular {  @include glyphBefore($glyph-icon-autoflow-tabular); }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								platform/commonUI/general/res/sass/_limits.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								platform/commonUI/general/res/sass/_limits.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
@mixin limitGlyph($iconColor, $glyph: $glyph-icon-alert-triangle) {
 | 
			
		||||
    &:before {
 | 
			
		||||
        color: $iconColor;
 | 
			
		||||
        content: $glyph;
 | 
			
		||||
        font-family: symbolsfont;
 | 
			
		||||
        font-size: 0.8em;
 | 
			
		||||
        display: inline;
 | 
			
		||||
        margin-right: $interiorMarginSm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-limit-red { background: $colorLimitRedBg !important; }
 | 
			
		||||
.s-limit-yellow { background: $colorLimitYellowBg !important; }
 | 
			
		||||
 | 
			
		||||
// Handle limit when applied to a tr
 | 
			
		||||
tr[class*="s-limit"] {
 | 
			
		||||
    &.s-limit-red td:first-child {
 | 
			
		||||
        @include limitGlyph($colorLimitRedIc);
 | 
			
		||||
    }
 | 
			
		||||
    &.s-limit-yellow td:first-child {
 | 
			
		||||
        @include limitGlyph($colorLimitYellowIc);
 | 
			
		||||
    }
 | 
			
		||||
    &.s-limit-upr td:first-child:before { content: $glyph-icon-arrow-double-up; }
 | 
			
		||||
    &.s-limit-lwr td:first-child:before { content: $glyph-icon-arrow-double-down; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle limit when applied directly to a non-tr element
 | 
			
		||||
// Assume this is applied to the element that displays the limit value
 | 
			
		||||
:not(tr)[class*="s-limit"] {
 | 
			
		||||
    &.s-limit-red {
 | 
			
		||||
        @include limitGlyph($colorLimitRedIc);
 | 
			
		||||
    }
 | 
			
		||||
    &.s-limit-yellow {
 | 
			
		||||
        @include limitGlyph($colorLimitYellowIc);
 | 
			
		||||
    }
 | 
			
		||||
    &.s-limit-upr:before { content: $glyph-icon-arrow-double-up; }
 | 
			
		||||
    &.s-limit-lwr:before { content: $glyph-icon-arrow-double-down; }
 | 
			
		||||
}
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
@import "about";
 | 
			
		||||
@import "text";
 | 
			
		||||
@import "icons";
 | 
			
		||||
@import "status";
 | 
			
		||||
@import "limits";
 | 
			
		||||
@import "data-status";
 | 
			
		||||
@import "helpers/bubbles";
 | 
			
		||||
@import "helpers/splitter";
 | 
			
		||||
@@ -37,7 +37,7 @@
 | 
			
		||||
/********************************* CONTROLS */
 | 
			
		||||
@import "controls/breadcrumb";
 | 
			
		||||
@import "controls/buttons";
 | 
			
		||||
@import "controls/color-palette";
 | 
			
		||||
@import "controls/palette";
 | 
			
		||||
@import "controls/controls";
 | 
			
		||||
@import "controls/lists";
 | 
			
		||||
@import "controls/menus";
 | 
			
		||||
@@ -80,3 +80,4 @@
 | 
			
		||||
@import "autoflow";
 | 
			
		||||
@import "features/imagery";
 | 
			
		||||
@import "features/time-display";
 | 
			
		||||
@import "widgets";
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,8 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@mixin absPosDefault($offset: 0px, $overflowHidden: hidden) {
 | 
			
		||||
    overflow: $overflowHidden;
 | 
			
		||||
@mixin absPosDefault($offset: 0px, $overflow: hidden) {
 | 
			
		||||
    overflow: $overflow;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: $offset;
 | 
			
		||||
    right: $offset;
 | 
			
		||||
@@ -316,28 +316,23 @@
 | 
			
		||||
    text-shadow: $shdwItemText;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin input-base() {
 | 
			
		||||
@mixin input-base($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
 | 
			
		||||
	@include appearance(none);
 | 
			
		||||
	border-radius: $controlCr;
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
    &:focus { outline: 0; }
 | 
			
		||||
	box-shadow: inset $shdw;
 | 
			
		||||
	background: $bg;
 | 
			
		||||
	border: none;
 | 
			
		||||
	color: $fg;
 | 
			
		||||
	outline: none;
 | 
			
		||||
	&.error {
 | 
			
		||||
		background-color: $colorFormFieldErrorBg;
 | 
			
		||||
        color: $colorFormFieldErrorFg;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin s-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
 | 
			
		||||
    @include input-base();
 | 
			
		||||
    background: $bg;
 | 
			
		||||
    box-shadow: inset $shdw;
 | 
			
		||||
    color: $fg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
 | 
			
		||||
    @include s-input($bg, $fg, $shdw);
 | 
			
		||||
    border: none;
 | 
			
		||||
    outline: none;
 | 
			
		||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg) {
 | 
			
		||||
	@include input-base($bg, $fg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin contextArrow() {
 | 
			
		||||
@@ -349,7 +344,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin nice-textarea($bg: $colorBodyBg, $fg: $colorBodyFg) {
 | 
			
		||||
    @include nice-input($bg, $fg);
 | 
			
		||||
    @include input-base($bg, $fg);
 | 
			
		||||
    padding: $interiorMargin;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,86 +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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*************************************************** MIXINS */
 | 
			
		||||
@mixin formulateStatusColors($c) {
 | 
			
		||||
    // Sets bg and icon colors for elements
 | 
			
		||||
    background: rgba($c, 0.4) !important;
 | 
			
		||||
    &:before { color: $c !important; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************** GENERAL */
 | 
			
		||||
.s-limit-yellow,
 | 
			
		||||
.s-limit-red,
 | 
			
		||||
.s-limit-yellow-icon,
 | 
			
		||||
.s-limit-red-icon,
 | 
			
		||||
.s-status-warning-lo,
 | 
			
		||||
.s-status-warning-hi,
 | 
			
		||||
.s-status-diagnostic,
 | 
			
		||||
.s-status-command,
 | 
			
		||||
.s-status-info,
 | 
			
		||||
.s-status-ok,
 | 
			
		||||
.s-status-warning-lo-icon,
 | 
			
		||||
.s-status-warning-hi-icon,
 | 
			
		||||
.s-status-diagnostic-icon,
 | 
			
		||||
.s-status-command-icon,
 | 
			
		||||
.s-status-info-icon,
 | 
			
		||||
.s-status-ok-icon {
 | 
			
		||||
    @include trans-prop-nice($props: background, $dur: 500ms);
 | 
			
		||||
    &:before {
 | 
			
		||||
        content:'';
 | 
			
		||||
        font-family: symbolsfont;
 | 
			
		||||
        font-size: 0.8em;
 | 
			
		||||
        display: inline;
 | 
			
		||||
        margin-right: $interiorMarginSm;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************** LIMITS */
 | 
			
		||||
.s-limit-yellow, .s-limit-yellow-icon {
 | 
			
		||||
    @include formulateStatusColors($colorWarningLo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-limit-red, .s-limit-red-icon {
 | 
			
		||||
    @include formulateStatusColors($colorWarningHi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-limit-upr:before { content: $glyph-icon-arrow-double-up; }
 | 
			
		||||
.s-limit-lwr:before { content: $glyph-icon-arrow-double-down; }
 | 
			
		||||
.s-limit-yellow-icon:before,
 | 
			
		||||
.s-limit-red-icon:before { content: $glyph-icon-alert-triangle; }
 | 
			
		||||
 | 
			
		||||
/*************************************************** STATUS */
 | 
			
		||||
.s-status-warning-hi, .s-status-warning-hi-icon {  @include formulateStatusColors($colorWarningHi); }
 | 
			
		||||
.s-status-warning-lo, .s-status-warning-lo-icon {  @include formulateStatusColors($colorWarningLo); }
 | 
			
		||||
.s-status-diagnostic, .s-status-diagnostic-icon {  @include formulateStatusColors($colorDiagnostic); }
 | 
			
		||||
.s-status-info, .s-status-info-icon {  @include formulateStatusColors($colorInfo); }
 | 
			
		||||
.s-status-ok, .s-status-ok-icon {  @include formulateStatusColors($colorOk); }
 | 
			
		||||
 | 
			
		||||
.s-status-warning-hi-icon:before { content: $glyph-icon-alert-triangle; }
 | 
			
		||||
.s-status-warning-lo-icon:before { content: $glyph-icon-alert-rect; }
 | 
			
		||||
.s-status-diagnostic-icon:before { content: $glyph-icon-eye-open; }
 | 
			
		||||
.s-status-info-icon:before { content: $glyph-icon-info; }
 | 
			
		||||
.s-status-ok-icon:before { content: $glyph-icon-check; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										213
									
								
								platform/commonUI/general/res/sass/_widgets.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								platform/commonUI/general/res/sass/_widgets.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,213 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/************************************************************* WIDGET OBJECT */
 | 
			
		||||
.l-summary-widget {
 | 
			
		||||
    // Widget layout classes here
 | 
			
		||||
    @include ellipsize();
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-summary-widget {
 | 
			
		||||
    // Widget style classes here
 | 
			
		||||
    border-radius: $basicCr;
 | 
			
		||||
    border-style: solid;
 | 
			
		||||
    border-width: 1px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: $interiorMarginLg $interiorMarginLg * 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-widget-outer-w,
 | 
			
		||||
.widget-holder,
 | 
			
		||||
.widget-edit-holder {
 | 
			
		||||
    // In browse mode, all these things should be at .abs default
 | 
			
		||||
    @extend .abs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.widget-edit-holder {
 | 
			
		||||
    // Hide edit area when in browse mode
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.widget-rule-header {
 | 
			
		||||
    @extend .l-flex-row;
 | 
			
		||||
    @include align-items(center);
 | 
			
		||||
    margin-bottom: $interiorMargin;
 | 
			
		||||
    > .flex-elem {
 | 
			
		||||
        &:not(:first-child) {
 | 
			
		||||
            margin-left: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.widget-rule-content {
 | 
			
		||||
    @include trans-prop-nice($props: (height, min-height), $dur: 250ms);
 | 
			
		||||
    min-height: 0;
 | 
			
		||||
    height: 0;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    &.expanded {
 | 
			
		||||
        min-height: 50px;
 | 
			
		||||
        height: auto;
 | 
			
		||||
        overflow: visible;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-widget-thumb-w,
 | 
			
		||||
.l-compact-form label {
 | 
			
		||||
    $ruleLabelW: 40%;
 | 
			
		||||
    $ruleLabelMaxW: 150px;
 | 
			
		||||
    @include display(flex);
 | 
			
		||||
    max-width: $ruleLabelMaxW;
 | 
			
		||||
    width: $ruleLabelW;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/********************************************************** EDITING A WIDGET */
 | 
			
		||||
.s-status-editing .l-widget-outer-w {
 | 
			
		||||
    $widgetHolderH: 100px;
 | 
			
		||||
    @extend .abs;
 | 
			
		||||
    //overflow: hidden; // Overflow scroll is handled by internal elements
 | 
			
		||||
 | 
			
		||||
    .widget-holder {
 | 
			
		||||
        bottom: auto;
 | 
			
		||||
        height: $widgetHolderH;
 | 
			
		||||
        .l-summary-widget {
 | 
			
		||||
            display: inline-block;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            top: 50%; left: 50%;
 | 
			
		||||
            @include transform(translateX(-50%) translateY(-50%));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .widget-edit-holder {
 | 
			
		||||
        @extend .l-flex-col;
 | 
			
		||||
        display: block; // Needed to counteract display: none while browsing
 | 
			
		||||
        overflow-y: scroll;
 | 
			
		||||
        padding-right: $interiorMargin;
 | 
			
		||||
        top: $widgetHolderH + $interiorMargin;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    .widget-test-data,
 | 
			
		||||
    .widget-rules-w {
 | 
			
		||||
        @include test(blue, 0.1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .widget-test-data {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .widget-rules-w {
 | 
			
		||||
        // Wrapper area that holds n rules
 | 
			
		||||
        @extend .flex-elem;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        font-size: 0.8em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .l-widget-rule {
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        margin-bottom: $interiorMargin;
 | 
			
		||||
        padding: $interiorMarginLg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .l-widget-thumb-w {
 | 
			
		||||
        @extend .l-flex-row;
 | 
			
		||||
        @include align-items(center);
 | 
			
		||||
        > span { display: block; }
 | 
			
		||||
        .grippy-holder,
 | 
			
		||||
        .view-control {
 | 
			
		||||
            margin-right: $interiorMargin;
 | 
			
		||||
            width: 1em;
 | 
			
		||||
            height: 1em;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .widget-thumb {
 | 
			
		||||
            @include flex(1 1 auto);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .rule-title {
 | 
			
		||||
        @include flex(0 1 auto);
 | 
			
		||||
        color: pullForward($colorBodyFg, 50%);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .rule-description {
 | 
			
		||||
        @include flex(1 1 auto);
 | 
			
		||||
        @include ellipsize();
 | 
			
		||||
        color: pushBack($colorBodyFg, 20%);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .s-widget-rule {
 | 
			
		||||
        background-color: rgba($colorBodyFg, 0.1);
 | 
			
		||||
        border-radius: $basicCr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .widget-thumb {
 | 
			
		||||
        @include ellipsize();
 | 
			
		||||
        @extend .s-summary-widget;
 | 
			
		||||
        @extend .l-summary-widget;
 | 
			
		||||
        padding: $interiorMarginSm $interiorMargin;
 | 
			
		||||
        .widget-icon {
 | 
			
		||||
            font-size: 0.8em;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Hide and show elements in the rule-header on hover
 | 
			
		||||
    .l-widget-rule {
 | 
			
		||||
        .grippy,
 | 
			
		||||
        .l-rule-action-buttons-w,
 | 
			
		||||
        .l-condition-action-buttons-w {
 | 
			
		||||
            @include trans-prop-nice($props: opacity, $dur: 500ms);
 | 
			
		||||
            opacity: 0;
 | 
			
		||||
        }
 | 
			
		||||
        &:hover {
 | 
			
		||||
            .grippy,
 | 
			
		||||
            .l-rule-action-buttons-w,
 | 
			
		||||
            .l-condition-action-buttons-w {
 | 
			
		||||
                @include trans-prop-nice($props: opacity, $dur: 0);
 | 
			
		||||
                opacity: 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    .l-compact-form {
 | 
			
		||||
        // Overrides
 | 
			
		||||
        ul li {
 | 
			
		||||
            padding: $interiorMargin 0;
 | 
			
		||||
            &:not(.widget-rule-header) {
 | 
			
		||||
                &:not(.connects-to-previous) {
 | 
			
		||||
                    border-top: 1px solid $colorFormLines;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            &.connects-to-previous {
 | 
			
		||||
                padding: $interiorMargin 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        label {
 | 
			
		||||
            display: block; // Needed to align text to right
 | 
			
		||||
            text-align: right;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -33,6 +33,7 @@ $pad: $interiorMargin * $baseRatio;
 | 
			
		||||
    height: $btnStdH;
 | 
			
		||||
    line-height: $btnStdH;
 | 
			
		||||
    padding: 0 $pad;
 | 
			
		||||
    vertical-align: top;
 | 
			
		||||
 | 
			
		||||
    &.labeled:before {
 | 
			
		||||
        // Icon when it's included
 | 
			
		||||
 
 | 
			
		||||
@@ -72,13 +72,11 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hyperlink objects
 | 
			
		||||
.s-hyperlink {
 | 
			
		||||
    .label {
 | 
			
		||||
        font-size: 0.8rem !important;
 | 
			
		||||
    }
 | 
			
		||||
    // Hyperlink objects
 | 
			
		||||
    &:not(.s-button) {
 | 
			
		||||
        color: $colorKey;
 | 
			
		||||
        font-size: 0.8rem;
 | 
			
		||||
        &:hover { color: $colorKeyHov; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -234,16 +232,12 @@ textarea {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** INPUTS */
 | 
			
		||||
%input-base {
 | 
			
		||||
    @include input-base();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type="text"],
 | 
			
		||||
input[type="search"],
 | 
			
		||||
input[type="number"] {
 | 
			
		||||
    @include nice-input();
 | 
			
		||||
    vertical-align: baseline;
 | 
			
		||||
    padding: $inputTextPTopBtm $inputTextPLeftRight;
 | 
			
		||||
    padding: $inputTextP;
 | 
			
		||||
    &.numeric {
 | 
			
		||||
        text-align: right;
 | 
			
		||||
    }
 | 
			
		||||
@@ -287,48 +281,20 @@ textarea.lg { position: relative; height: 300px; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
*[contenteditable].s-input-inline,
 | 
			
		||||
input[type="text"].s-input-inline,
 | 
			
		||||
.s-input-inline input[type="text"] {
 | 
			
		||||
    // A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
 | 
			
		||||
    @extend %input-base;
 | 
			
		||||
    @include trans-prop-nice((padding, box-shadow), 250ms);
 | 
			
		||||
    background: none;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    border: 1px solid transparent;
 | 
			
		||||
    min-width: 20px;
 | 
			
		||||
    padding-left: 0;
 | 
			
		||||
    padding-right: 0;
 | 
			
		||||
    &:hover,
 | 
			
		||||
    &:focus {
 | 
			
		||||
        padding-left: $inputTextPLeftRight;
 | 
			
		||||
        padding-right: $inputTextPLeftRight;
 | 
			
		||||
    }
 | 
			
		||||
    &:hover {
 | 
			
		||||
        border-color: rgba($colorBodyFg, 0.2);
 | 
			
		||||
    }
 | 
			
		||||
    &:focus {
 | 
			
		||||
        @include s-input();
 | 
			
		||||
        border-color: transparent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** SELECTS */
 | 
			
		||||
.select {
 | 
			
		||||
    @include btnSubtle($bg: $colorSelectBg);
 | 
			
		||||
    @extend .icon-arrow-down; // Context arrow
 | 
			
		||||
    @if $shdwBtns != none {
 | 
			
		||||
        margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
 | 
			
		||||
    }
 | 
			
		||||
    //@if $shdwBtns != none { margin: 0 0 2px 0; } // Needed to avoid dropshadow from being clipped by parent containers
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    padding: 0 $interiorMargin;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    line-height: $formInputH;
 | 
			
		||||
    height: $btnStdH;
 | 
			
		||||
    line-height: $btnStdH;
 | 
			
		||||
    select {
 | 
			
		||||
        @include appearance(none);
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        &:focus { outline: 0; }
 | 
			
		||||
        background: none;
 | 
			
		||||
        color: $colorSelectFg;
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
@@ -340,11 +306,13 @@ input[type="text"].s-input-inline,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    &:before {
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
        @include transform(translateY(-50%));
 | 
			
		||||
        color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
 | 
			
		||||
        display: block;
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        right: $interiorMargin; top: 0;
 | 
			
		||||
        right: $interiorMargin;
 | 
			
		||||
        top: 50%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -736,6 +704,30 @@ textarea {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.view-switcher,
 | 
			
		||||
.t-btn-view-large {
 | 
			
		||||
    @include trans-prop-nice-fade($controlFadeMs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.view-control {
 | 
			
		||||
    @extend .icon-arrow-right;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    font-size: 0.75em;
 | 
			
		||||
    &:before {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        @include trans-prop-nice(transform, 100ms);
 | 
			
		||||
        @include transform-origin(center);
 | 
			
		||||
    }
 | 
			
		||||
    &.expanded:before {
 | 
			
		||||
        @include transform(rotate(90deg));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grippy {
 | 
			
		||||
    @extend .icon-grippy;
 | 
			
		||||
    cursor: move;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** BROWSER ELEMENTS */
 | 
			
		||||
body.desktop {
 | 
			
		||||
    ::-webkit-scrollbar {
 | 
			
		||||
@@ -753,15 +745,11 @@ body.desktop {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .overlay ::-webkit-scrollbar-thumb {
 | 
			
		||||
        $lr: 15%;
 | 
			
		||||
        background: $scrollbarThumbColorOverlay;
 | 
			
		||||
        &:hover { background: $scrollbarThumbColorOverlayHov; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .menu ::-webkit-scrollbar-thumb {
 | 
			
		||||
        background: $scrollbarThumbColorMenu;
 | 
			
		||||
        &:hover { background: $scrollbarThumbColorMenuHov; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::-webkit-scrollbar-corner {
 | 
			
		||||
        background: $scrollbarTrackColorBg;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -21,87 +21,97 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/******************************************************** MENU BUTTONS */
 | 
			
		||||
.s-menu-button {
 | 
			
		||||
    // Formerly .btn-menu
 | 
			
		||||
    @extend .s-button;
 | 
			
		||||
    span.l-click-area {
 | 
			
		||||
        // In markup, this element should not enclose anything.
 | 
			
		||||
        @extend .abs;
 | 
			
		||||
    }
 | 
			
		||||
	// Formerly .btn-menu
 | 
			
		||||
	@extend .s-button;
 | 
			
		||||
	span.l-click-area {
 | 
			
		||||
		// In markup, this element should not enclose anything.
 | 
			
		||||
		@extend .abs;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    .icon {
 | 
			
		||||
        font-size: 16px; //120%;
 | 
			
		||||
    }
 | 
			
		||||
	.icon {
 | 
			
		||||
		font-size: 16px; //120%;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    .title-label {
 | 
			
		||||
        margin-left: $interiorMarginSm;
 | 
			
		||||
    }
 | 
			
		||||
	.title-label {
 | 
			
		||||
		margin-left: $interiorMarginSm;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    .icon-swatch,
 | 
			
		||||
    .color-swatch {
 | 
			
		||||
        // Used in color menu buttons in toolbar
 | 
			
		||||
        $d: 10px;
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        border: 1px solid rgba($colorBtnFg, 0.2);
 | 
			
		||||
        height: $d;
 | 
			
		||||
        width: $d;
 | 
			
		||||
        height: $d; width: $d;
 | 
			
		||||
        line-height: $d;
 | 
			
		||||
        vertical-align: middle;
 | 
			
		||||
        margin-left: $interiorMarginSm;
 | 
			
		||||
        margin-top: -2px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:after {
 | 
			
		||||
        // Adds the downward facing 'context available / invoke menu' arrow element
 | 
			
		||||
        @include contextArrow();
 | 
			
		||||
        color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.create-button {
 | 
			
		||||
        @extend .icon-plus;
 | 
			
		||||
        .title-label {
 | 
			
		||||
            font-size: 1rem;
 | 
			
		||||
        &:not(.no-selection) {
 | 
			
		||||
            border-color: transparent;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .menu {
 | 
			
		||||
        left: 0;
 | 
			
		||||
        text-align: left;
 | 
			
		||||
    }
 | 
			
		||||
	&:after {
 | 
			
		||||
		// Adds the downward facing 'context available / invoke menu' arrow element
 | 
			
		||||
		@include contextArrow();
 | 
			
		||||
		color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	&.create-button {
 | 
			
		||||
        @extend .icon-plus;
 | 
			
		||||
		.title-label {
 | 
			
		||||
			font-size: 1rem;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.menu {
 | 
			
		||||
		left: 0;
 | 
			
		||||
		text-align: left;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** MENUS THEMSELVES */
 | 
			
		||||
.menu-element {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    position: relative;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-menu {
 | 
			
		||||
	border-radius: $basicCr;
 | 
			
		||||
	@include containerSubtle($colorMenuBg, $colorMenuFg);
 | 
			
		||||
	@include boxShdw($shdwMenu);
 | 
			
		||||
	@include txtShdw($shdwMenuText);
 | 
			
		||||
	padding: $interiorMarginSm 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menu {
 | 
			
		||||
    border-radius: $basicCr;
 | 
			
		||||
    @include containerSubtle($colorMenuBg, $colorMenuFg);
 | 
			
		||||
    @include boxShdw($shdwMenu);
 | 
			
		||||
    @include txtShdw($shdwMenuText);
 | 
			
		||||
    padding: $interiorMarginSm 0;
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
    ul {
 | 
			
		||||
        @include menuUlReset();
 | 
			
		||||
        li {
 | 
			
		||||
            box-sizing: border-box;
 | 
			
		||||
            border-top: 1px solid pullForward($colorMenuBg, 10%);
 | 
			
		||||
    // TODO: reduce size of icons
 | 
			
		||||
	@extend .s-menu;
 | 
			
		||||
	display: block;
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	z-index: 10;
 | 
			
		||||
	ul {
 | 
			
		||||
		@include menuUlReset();
 | 
			
		||||
		li {
 | 
			
		||||
			box-sizing: border-box;
 | 
			
		||||
			border-top: 1px solid pullForward($colorMenuBg, 10%);
 | 
			
		||||
            color: $colorMenuFg;
 | 
			
		||||
            line-height: $menuLineH;
 | 
			
		||||
            padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
 | 
			
		||||
            position: relative;
 | 
			
		||||
            white-space: nowrap;
 | 
			
		||||
            &:first-child {
 | 
			
		||||
                border: none;
 | 
			
		||||
            }
 | 
			
		||||
            &:hover {
 | 
			
		||||
                background: $colorMenuHovBg;
 | 
			
		||||
                color: $colorMenuHovFg;
 | 
			
		||||
			//color: pullForward($colorMenuBg, 60%);
 | 
			
		||||
			line-height: $menuLineH;
 | 
			
		||||
			padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
 | 
			
		||||
			position: relative;
 | 
			
		||||
			white-space: nowrap;
 | 
			
		||||
			&:first-child {
 | 
			
		||||
				border: none;
 | 
			
		||||
			}
 | 
			
		||||
			&:hover {
 | 
			
		||||
				background: $colorMenuHovBg;
 | 
			
		||||
				color: $colorMenuHovFg;
 | 
			
		||||
                &:before {
 | 
			
		||||
                    color: $colorMenuHovIc;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
			}
 | 
			
		||||
            &:before {
 | 
			
		||||
                @extend .ui-symbol;
 | 
			
		||||
                @extend .type-icon;
 | 
			
		||||
@@ -109,8 +119,8 @@
 | 
			
		||||
                display: inline-block;
 | 
			
		||||
                left: $interiorMargin * 2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menu,
 | 
			
		||||
@@ -118,97 +128,94 @@
 | 
			
		||||
.context-menu,
 | 
			
		||||
.super-menu,
 | 
			
		||||
.s-menu-button .menu {
 | 
			
		||||
    pointer-events: auto;
 | 
			
		||||
    ul li {
 | 
			
		||||
        a.menu-item-a {
 | 
			
		||||
	pointer-events: auto;
 | 
			
		||||
	ul li {
 | 
			
		||||
		a.menu-item-a {
 | 
			
		||||
            color: $colorMenuFg;
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
		}
 | 
			
		||||
        &:before,
 | 
			
		||||
        a.menu-item-a:before {
 | 
			
		||||
            color: $colorMenuIc;
 | 
			
		||||
            left: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.checkbox-menu {
 | 
			
		||||
    // Used in search dropdown in tree
 | 
			
		||||
    @extend .context-menu;
 | 
			
		||||
    ul li {
 | 
			
		||||
        padding-left: 50px;
 | 
			
		||||
        .checkbox {
 | 
			
		||||
            $d: 0.7rem;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            left: $interiorMargin;
 | 
			
		||||
            top: ($menuLineH - $d) / 1.5;
 | 
			
		||||
            em {
 | 
			
		||||
                height: $d;
 | 
			
		||||
                width: $d;
 | 
			
		||||
                &:before {
 | 
			
		||||
                    font-size: 7px !important;
 | 
			
		||||
                    height: $d;
 | 
			
		||||
                    width: $d;
 | 
			
		||||
                    line-height: $d;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        &:before {
 | 
			
		||||
	// Used in search dropdown in tree
 | 
			
		||||
	@extend .context-menu;
 | 
			
		||||
	ul li {
 | 
			
		||||
		padding-left: 50px;
 | 
			
		||||
		.checkbox {
 | 
			
		||||
			$d: 0.7rem;
 | 
			
		||||
			position: absolute;
 | 
			
		||||
			left: $interiorMargin;
 | 
			
		||||
			top: ($menuLineH - $d) / 1.5;
 | 
			
		||||
			em {
 | 
			
		||||
				height: $d;
 | 
			
		||||
				width: $d;
 | 
			
		||||
				&:before {
 | 
			
		||||
					font-size: 7px !important;
 | 
			
		||||
					height: $d;
 | 
			
		||||
					width: $d;
 | 
			
		||||
					line-height: $d;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		&:before {
 | 
			
		||||
            // Type icon
 | 
			
		||||
            left: 25px;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.super-menu,
 | 
			
		||||
.super-menu > mct-representation,
 | 
			
		||||
.super-menu > .contents {
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: relative;
 | 
			
		||||
			left: 25px;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.super-menu {
 | 
			
		||||
    $plw: 50%;
 | 
			
		||||
    $prw: 100% - $plw;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    .w-menu {
 | 
			
		||||
        align-items: stretch;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: row;
 | 
			
		||||
        margin: $interiorMarginLg;
 | 
			
		||||
    }
 | 
			
		||||
    .col {
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        flex: 1 1 auto;
 | 
			
		||||
        overflow-x: hidden;
 | 
			
		||||
        &.menu-items {
 | 
			
		||||
            border-right: 1px solid pullForward($colorMenuBg, 10%);
 | 
			
		||||
            overflow-y: auto;
 | 
			
		||||
            padding-right: $interiorMargin;
 | 
			
		||||
            width: $plw;
 | 
			
		||||
            ul {
 | 
			
		||||
                li {
 | 
			
		||||
                    border-radius: $controlCr;
 | 
			
		||||
                    padding-left: 30px;
 | 
			
		||||
                    border-top: none;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        &.menu-item-description {
 | 
			
		||||
            $p: $interiorMargin * 3;
 | 
			
		||||
            overflow-y: hidden;
 | 
			
		||||
            padding: $p $p 0 $p;
 | 
			
		||||
            width: $prw;
 | 
			
		||||
 | 
			
		||||
	$w: 500px;
 | 
			
		||||
	$h: $w - 20;
 | 
			
		||||
	$plw: 50%;
 | 
			
		||||
	$prw: 50%;
 | 
			
		||||
	display: block;
 | 
			
		||||
	width: $w;
 | 
			
		||||
	height: $h;
 | 
			
		||||
	.contents {
 | 
			
		||||
		@include absPosDefault($interiorMargin);
 | 
			
		||||
	}
 | 
			
		||||
	.pane {
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
		&.menu-items {
 | 
			
		||||
			border-right: 1px solid pullForward($colorMenuBg, 10%);
 | 
			
		||||
			left: 0;
 | 
			
		||||
			padding-right: $interiorMargin;
 | 
			
		||||
			right: auto;
 | 
			
		||||
			width: $plw;
 | 
			
		||||
			overflow-x: hidden;
 | 
			
		||||
			overflow-y: auto;
 | 
			
		||||
			ul {
 | 
			
		||||
				li {
 | 
			
		||||
					border-radius: $controlCr;
 | 
			
		||||
					padding-left: 30px;
 | 
			
		||||
					border-top: none;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		&.menu-item-description {
 | 
			
		||||
			left: auto;
 | 
			
		||||
			right: 0;
 | 
			
		||||
			padding: $interiorMargin * 5;
 | 
			
		||||
			width: $prw;
 | 
			
		||||
            .desc-area {
 | 
			
		||||
                &.icon {
 | 
			
		||||
                    color: $colorCreateMenuLgIcon;
 | 
			
		||||
                    font-size: 8em;
 | 
			
		||||
                    margin-bottom: $interiorMargin * 3;
 | 
			
		||||
                    position: relative;
 | 
			
		||||
                    text-align: center;
 | 
			
		||||
                }
 | 
			
		||||
                &.title {
 | 
			
		||||
                    color: $colorCreateMenuText;
 | 
			
		||||
                    font-size: 1.2em;
 | 
			
		||||
                    margin-bottom: $interiorMargin * 2;
 | 
			
		||||
                }
 | 
			
		||||
                &.description {
 | 
			
		||||
                    color: pushBack($colorCreateMenuText, 20%);
 | 
			
		||||
@@ -216,104 +223,67 @@
 | 
			
		||||
                    line-height: 1.5em;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .w-title-desc {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        overflow: hidden; // Height set in specific menu instances
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specific menu instances
 | 
			
		||||
    &.l-create-menu {
 | 
			
		||||
        width: 500px;
 | 
			
		||||
        .col {
 | 
			
		||||
            max-height: 70vh;
 | 
			
		||||
        }
 | 
			
		||||
        .w-title-desc {
 | 
			
		||||
            height: 190px;
 | 
			
		||||
        }
 | 
			
		||||
        .desc-area {
 | 
			
		||||
            &.icon {
 | 
			
		||||
                font-size: 8em;
 | 
			
		||||
                height: 135px;
 | 
			
		||||
                margin-bottom: $interiorMargin * 3;
 | 
			
		||||
            }
 | 
			
		||||
            &.title {
 | 
			
		||||
                font-size: 1.2em;
 | 
			
		||||
                margin-bottom: $interiorMargin * 2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    &.mini {
 | 
			
		||||
        width: 400px;
 | 
			
		||||
        .col {
 | 
			
		||||
            max-height: 50vh;
 | 
			
		||||
        height: 300px;
 | 
			
		||||
        .pane {
 | 
			
		||||
            &.menu-items {
 | 
			
		||||
                font-size: 0.8em;
 | 
			
		||||
            }
 | 
			
		||||
            &.menu-item-description {
 | 
			
		||||
                $p: $interiorMargin * 2;
 | 
			
		||||
                padding: $p $p 0 $p;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .w-title-desc {
 | 
			
		||||
            height: 180px;
 | 
			
		||||
        }
 | 
			
		||||
        .desc-area {
 | 
			
		||||
            &.icon {
 | 
			
		||||
                font-size: 4em;
 | 
			
		||||
                height: 70px;
 | 
			
		||||
                margin-bottom: $interiorMargin * 3;
 | 
			
		||||
            }
 | 
			
		||||
            &.title {
 | 
			
		||||
                font-size: 1em;
 | 
			
		||||
                margin-bottom: $interiorMargin * 2;
 | 
			
		||||
                padding: $interiorMargin * 3;
 | 
			
		||||
                .desc-area {
 | 
			
		||||
                    &.icon {
 | 
			
		||||
                        font-size: 4em;
 | 
			
		||||
                    }
 | 
			
		||||
                    &.title {
 | 
			
		||||
                        font-size: 1em;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.context-menu {
 | 
			
		||||
    font-size: 0.80rem;
 | 
			
		||||
	font-size: 0.80rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.context-menu-holder,
 | 
			
		||||
.menu-holder {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 120;
 | 
			
		||||
    .context-menu-wrapper {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
    &.go-left .context-menu,
 | 
			
		||||
    &.go-left .menu {
 | 
			
		||||
        right: 0;
 | 
			
		||||
    }
 | 
			
		||||
    &.go-up .context-menu,
 | 
			
		||||
    &.go-up .menu {
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	z-index: 120;
 | 
			
		||||
	.context-menu-wrapper {
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		width: 100%;
 | 
			
		||||
	}
 | 
			
		||||
	&.go-left .context-menu,
 | 
			
		||||
	&.go-left .menu {
 | 
			
		||||
		right: 0;
 | 
			
		||||
	}
 | 
			
		||||
	&.go-up .context-menu,
 | 
			
		||||
	&.go-up .menu {
 | 
			
		||||
		bottom: 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.context-menu-holder {
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
    height: 200px;
 | 
			
		||||
    width: 170px;
 | 
			
		||||
	pointer-events: none;
 | 
			
		||||
	height: 200px;
 | 
			
		||||
	width: 170px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn-bar.right .menu,
 | 
			
		||||
.menus-to-left .menu {
 | 
			
		||||
    z-index: 79;
 | 
			
		||||
    left: auto;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    width: auto;
 | 
			
		||||
	left: auto;
 | 
			
		||||
	right: 0;
 | 
			
		||||
	width: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menus-up .menu {
 | 
			
		||||
    bottom: $btnStdH;
 | 
			
		||||
    top: auto;
 | 
			
		||||
    bottom: $btnStdH; top: auto;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@
 | 
			
		||||
// Status coloring
 | 
			
		||||
.ok, .info {
 | 
			
		||||
    .status-indicator {
 | 
			
		||||
        color: $colorInfo;
 | 
			
		||||
        color: $colorStatusInfo;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -224,15 +224,15 @@
 | 
			
		||||
	}
 | 
			
		||||
	&.ok,
 | 
			
		||||
    &.info {
 | 
			
		||||
		@include statusBannerColors($colorInfo);
 | 
			
		||||
		@include statusBannerColors($colorStatusInfo);
 | 
			
		||||
	}
 | 
			
		||||
	&.caution,
 | 
			
		||||
    &.warning,
 | 
			
		||||
    &.alert {
 | 
			
		||||
		@include statusBannerColors($colorWarningLo);
 | 
			
		||||
		@include statusBannerColors($colorStatusAlert);
 | 
			
		||||
	}
 | 
			
		||||
    &.error {
 | 
			
		||||
        @include statusBannerColors($colorWarningHi);
 | 
			
		||||
        @include statusBannerColors($colorStatusError);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -248,15 +248,15 @@
 | 
			
		||||
 | 
			
		||||
    .message-severity-info .type-icon.message-type {
 | 
			
		||||
        @extend .icon-info;
 | 
			
		||||
        color: $colorInfo;
 | 
			
		||||
        color: $colorStatusInfo;
 | 
			
		||||
    }
 | 
			
		||||
    .message-severity-alert .type-icon.message-type {
 | 
			
		||||
        @extend .icon-bell;
 | 
			
		||||
        color: $colorWarningLo;
 | 
			
		||||
        color: $colorStatusAlert;
 | 
			
		||||
    }
 | 
			
		||||
    .message-severity-error .type-icon.message-type {
 | 
			
		||||
        @extend .icon-alert-rect;
 | 
			
		||||
        color: $colorWarningHi;
 | 
			
		||||
        color: $colorStatusError;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/* Paths:
 | 
			
		||||
 
 | 
			
		||||
@@ -19,11 +19,10 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.l-color-palette {
 | 
			
		||||
.l-palette {
 | 
			
		||||
	$d: 16px;
 | 
			
		||||
	$colorsPerRow: 10;
 | 
			
		||||
	$m: 1;
 | 
			
		||||
	$colorSelectedColor: #fff;
 | 
			
		||||
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
	padding: $interiorMargin !important;
 | 
			
		||||
@@ -33,46 +32,41 @@
 | 
			
		||||
		line-height: $d;
 | 
			
		||||
		width: ($d * $colorsPerRow) + ($m * $colorsPerRow);
 | 
			
		||||
 | 
			
		||||
        &.l-option-row {
 | 
			
		||||
            margin-bottom: $interiorMargin;
 | 
			
		||||
            .s-palette-item {
 | 
			
		||||
                border-color: $colorPaletteFg;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		.l-palette-item {
 | 
			
		||||
			box-sizing: border-box;
 | 
			
		||||
			@include txtShdwSubtle(0.8);
 | 
			
		||||
			@include trans-prop-nice-fade(0.25s);
 | 
			
		||||
			border: 1px solid transparent;
 | 
			
		||||
			color: $colorSelectedColor;
 | 
			
		||||
			display: block;
 | 
			
		||||
			float: left;
 | 
			
		||||
			height: $d; width: $d;
 | 
			
		||||
			line-height: $d * 0.9;
 | 
			
		||||
			margin: 0 ($m * 1px) ($m * 1px) 0;
 | 
			
		||||
            position: relative;
 | 
			
		||||
			text-align: center;
 | 
			
		||||
            &:before {
 | 
			
		||||
                // Check mark for selected items
 | 
			
		||||
                font-size: 0.8em;
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.s-palette-item {
 | 
			
		||||
            border: 1px solid transparent;
 | 
			
		||||
            color: $colorPaletteFg;
 | 
			
		||||
            text-shadow: $shdwPaletteFg;
 | 
			
		||||
            @include trans-prop-nice-fade(0.25s);
 | 
			
		||||
			&:hover {
 | 
			
		||||
				@include trans-prop-nice-fade(0);
 | 
			
		||||
				border-color: $colorSelectedColor !important;
 | 
			
		||||
				border-color: $colorPaletteSelected !important;
 | 
			
		||||
			}
 | 
			
		||||
            &.selected {
 | 
			
		||||
                border-color: $colorPaletteSelected;
 | 
			
		||||
                box-shadow: $shdwPaletteSelected; //Needed to see selection rect on light colored swatches
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.l-palette-item-label {
 | 
			
		||||
			margin-left: $interiorMargin;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		&.l-option-row {
 | 
			
		||||
			margin-bottom: $interiorMargin;
 | 
			
		||||
			.s-palette-item {
 | 
			
		||||
				border-color: $colorBodyFg;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
	@if $enableImageryThumbs == true {
 | 
			
		||||
		bottom: $interiorMargin*2 +  $imageThumbsWrapperH;
 | 
			
		||||
	}
 | 
			
		||||
	min-height: 100px;
 | 
			
		||||
	min-width: 150px;
 | 
			
		||||
	.l-image-main {
 | 
			
		||||
		background-color: $colorPlotBg;
 | 
			
		||||
@@ -21,9 +22,7 @@
 | 
			
		||||
 | 
			
		||||
.l-image-thumbs-wrapper {
 | 
			
		||||
	top: auto;
 | 
			
		||||
	min-height: $imageThumbsWrapperH;
 | 
			
		||||
	max-height: 60%;
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
	height: $imageThumbsWrapperH;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-date,
 | 
			
		||||
@@ -44,16 +43,14 @@
 | 
			
		||||
.l-image-main-controlbar {
 | 
			
		||||
	font-size: 0.8em;
 | 
			
		||||
	line-height: inherit;
 | 
			
		||||
	.l-datetime-w, .l-controls-w {
 | 
			
		||||
	.left, .right {
 | 
			
		||||
		direction: rtl;
 | 
			
		||||
		overflow: hidden;
 | 
			
		||||
	}
 | 
			
		||||
	.l-datetime-w {
 | 
			
		||||
        @include ellipsize();
 | 
			
		||||
        margin-right: $interiorMarginSm;
 | 
			
		||||
	.left {
 | 
			
		||||
		text-align: left;
 | 
			
		||||
	}
 | 
			
		||||
	.l-controls-w {
 | 
			
		||||
	.right {
 | 
			
		||||
		z-index: 2;
 | 
			
		||||
	}
 | 
			
		||||
	.l-date,
 | 
			
		||||
@@ -85,8 +82,9 @@
 | 
			
		||||
/*************************************** THUMBS */
 | 
			
		||||
 | 
			
		||||
.l-image-thumbs-wrapper {
 | 
			
		||||
	overflow-x: hidden;
 | 
			
		||||
	overflow-y: auto;
 | 
			
		||||
	//@include test(green);
 | 
			
		||||
	overflow-x: auto;
 | 
			
		||||
	overflow-y: hidden;
 | 
			
		||||
	padding-bottom: $interiorMargin;
 | 
			
		||||
	white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
@@ -94,17 +92,8 @@
 | 
			
		||||
.l-image-thumb-item {
 | 
			
		||||
	@include transition(background-color, 0.25s);
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    direction: ltr;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    float: left;
 | 
			
		||||
    font-size: 0.8em;
 | 
			
		||||
	padding: 1px;
 | 
			
		||||
    margin-left: $interiorMarginSm;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
    width: $imageThumbsD + $imageThumbPad*2;
 | 
			
		||||
    white-space: normal;
 | 
			
		||||
	position: relative;
 | 
			
		||||
	.l-thumb,
 | 
			
		||||
	.l-date,
 | 
			
		||||
	.l-time {
 | 
			
		||||
@@ -114,7 +103,14 @@
 | 
			
		||||
	.l-time {
 | 
			
		||||
		padding: 2px 3px;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	direction: ltr;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	font-size: 0.8em;
 | 
			
		||||
	margin-left: $interiorMarginSm;
 | 
			
		||||
	text-align: left;
 | 
			
		||||
	width: $imageThumbsD + $imageThumbPad*2;
 | 
			
		||||
	white-space: normal;
 | 
			
		||||
	&:hover {
 | 
			
		||||
		background: $colorThumbHoverBg;
 | 
			
		||||
		.l-date,
 | 
			
		||||
@@ -140,7 +136,6 @@
 | 
			
		||||
/*************************************** LOCAL CONTROLS */
 | 
			
		||||
.l-local-controls {
 | 
			
		||||
    max-width: 200px;
 | 
			
		||||
    min-width: 100px;
 | 
			
		||||
    width: 35%;
 | 
			
		||||
    input[type="range"] {
 | 
			
		||||
        display: block;
 | 
			
		||||
@@ -189,8 +184,7 @@
 | 
			
		||||
/*************************************** WHEN IN FRAME */
 | 
			
		||||
.frame .t-imagery {
 | 
			
		||||
	.l-image-main-wrapper {
 | 
			
		||||
		bottom: 0 !important;
 | 
			
		||||
        height: 100% !important;
 | 
			
		||||
		bottom: 0;
 | 
			
		||||
		.l-image-main-controlbar {
 | 
			
		||||
			font-size: 0.7em;
 | 
			
		||||
		}
 | 
			
		||||
@@ -200,8 +194,7 @@
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.l-image-thumbs-wrapper,
 | 
			
		||||
    mct-splitter {
 | 
			
		||||
	.l-image-thumbs-wrapper {
 | 
			
		||||
		display: none;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,12 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.section-header {
 | 
			
		||||
    border-radius: $basicCr;
 | 
			
		||||
    background: $colorFormSectionHeader;
 | 
			
		||||
    color: lighten($colorBodyFg, 20%);
 | 
			
		||||
    font-size: 0.8em;
 | 
			
		||||
    margin: $interiorMargin 0;
 | 
			
		||||
    padding: $formTBPad $formLRPad;
 | 
			
		||||
    text-transform: uppercase;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -41,15 +47,6 @@
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .section-header {
 | 
			
		||||
        border-radius: $basicCr;
 | 
			
		||||
        background: $colorFormSectionHeader;
 | 
			
		||||
        $c: lighten($colorBodyFg, 20%);
 | 
			
		||||
        color: $c;
 | 
			
		||||
        font-size: 0.8em;
 | 
			
		||||
        padding: $formTBPad $formLRPad;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	.form-row {
 | 
			
		||||
		$m: $interiorMargin;
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
@@ -171,3 +168,105 @@
 | 
			
		||||
		padding: $interiorMargin;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**************************************************************************** COMPACT FORM */
 | 
			
		||||
// ul > li > label, control
 | 
			
		||||
// Make a new UL for each form section
 | 
			
		||||
// Allow control-first, controls-below
 | 
			
		||||
// TO-DO: migrate work in branch ch-plot-styling that users .inspector-config to use classes below instead
 | 
			
		||||
 | 
			
		||||
.l-compact-form .tree ul li,
 | 
			
		||||
.l-compact-form ul li {
 | 
			
		||||
    padding: 2px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.l-compact-form {
 | 
			
		||||
    $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;
 | 
			
		||||
            }
 | 
			
		||||
            .controls {
 | 
			
		||||
                @include flex-grow(1);
 | 
			
		||||
                margin-left: $interiorMargin    ;
 | 
			
		||||
                .e-control {
 | 
			
		||||
                    // Individual form controls
 | 
			
		||||
                    &:not(:first-child) {
 | 
			
		||||
                        margin-left: $interiorMarginSm;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:not(.section-header) {
 | 
			
		||||
                &:not(.connects-to-previous) {
 | 
			
		||||
                    //border-top: 1px solid $colorFormLines;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.connects-to-previous {
 | 
			
		||||
                padding-top: 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -129,6 +129,9 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-filter {
 | 
			
		||||
    input[type="search"] {
 | 
			
		||||
        @include input-base();
 | 
			
		||||
    }
 | 
			
		||||
    .clear-icon,
 | 
			
		||||
    .menu-icon,
 | 
			
		||||
    &:before {
 | 
			
		||||
 
 | 
			
		||||
@@ -156,8 +156,6 @@
 | 
			
		||||
            left: 0;
 | 
			
		||||
            right: 0;
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            padding-right: $interiorMargin;
 | 
			
		||||
            padding-bottom: $interiorMargin;
 | 
			
		||||
            .field.l-input-med {
 | 
			
		||||
                input[type='text'] {
 | 
			
		||||
                    width: 100%;
 | 
			
		||||
 
 | 
			
		||||
@@ -52,21 +52,13 @@ ul.tree {
 | 
			
		||||
 | 
			
		||||
    .view-control {
 | 
			
		||||
        color: $colorItemTreeVC;
 | 
			
		||||
        font-size: 0.75em;
 | 
			
		||||
        margin-right: $interiorMargin;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        line-height: inherit;
 | 
			
		||||
        width: $treeVCW;
 | 
			
		||||
        &:before { display: none; }
 | 
			
		||||
        &.has-children {
 | 
			
		||||
            &:before {
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                @include trans-prop-nice(transform, 100ms);
 | 
			
		||||
                content: "\e904";
 | 
			
		||||
                @include transform-origin(center);
 | 
			
		||||
            }
 | 
			
		||||
            &.expanded:before {
 | 
			
		||||
                @include transform(rotate(90deg));
 | 
			
		||||
            }
 | 
			
		||||
            &:before { display: block; }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@
 | 
			
		||||
    &.t-object-type-hyperlink {
 | 
			
		||||
        // Hide the right side buttons for objects where they don't make sense
 | 
			
		||||
        // Note that this will hide the view Switcher button if applied
 | 
			
		||||
        // to an object that has it.
 | 
			
		||||
        // to an object that it.
 | 
			
		||||
        .object-browse-bar .right { display: none; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -120,17 +120,9 @@
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.t-frame-outer .s-input-inline {
 | 
			
		||||
        // Prevent inline inputs from being edited when nested in a Layout
 | 
			
		||||
        pointer-events: none !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /********************************************************** OBJECT TYPES */
 | 
			
		||||
    /********************************************************** OBJECT TYPES */
 | 
			
		||||
    .t-object-type-hyperlink {
 | 
			
		||||
        .object-holder {
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
        }
 | 
			
		||||
        .l-hyperlink.s-button {
 | 
			
		||||
        .s-hyperlink.s-button {
 | 
			
		||||
            // When a hyperlink is a button in a frame, make it expand to fill out to the object-holder
 | 
			
		||||
            @extend .abs;
 | 
			
		||||
            .label {
 | 
			
		||||
@@ -150,7 +142,7 @@
 | 
			
		||||
body.desktop .frame {
 | 
			
		||||
    // Hide local controls initially and show it them on hover when they're in an element that's in a frame context
 | 
			
		||||
    // Frame template is used because we need to target the lowest nested frame
 | 
			
		||||
    .object-browse-bar .btn-bar {
 | 
			
		||||
    .right {
 | 
			
		||||
        opacity: 0;
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
    }
 | 
			
		||||
@@ -158,7 +150,7 @@ body.desktop .frame {
 | 
			
		||||
    // Target the first descendant so that we only show the elements in the outermost container.
 | 
			
		||||
    // Handles the case where we have layouts in layouts.
 | 
			
		||||
    &:hover > .object-browse-bar {
 | 
			
		||||
        .btn-bar {
 | 
			
		||||
        .right {
 | 
			
		||||
            opacity: 1;
 | 
			
		||||
            pointer-events: inherit;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -240,9 +240,7 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
 | 
			
		||||
.top-bar .buttons-main .s-button,
 | 
			
		||||
.top-bar .s-menu-button,
 | 
			
		||||
.tool-bar .s-button,
 | 
			
		||||
.tool-bar .s-menu-button,
 | 
			
		||||
.tool-bar .select,
 | 
			
		||||
.tool-bar .input-labeled {
 | 
			
		||||
.tool-bar .s-menu-button {
 | 
			
		||||
    $h: $btnToolbarH;
 | 
			
		||||
    height: $h;
 | 
			
		||||
    line-height: $h;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,6 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.tool-bar {
 | 
			
		||||
    font-size: 0.7rem;
 | 
			
		||||
    &.btn-bar {
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
    }
 | 
			
		||||
@@ -31,7 +30,9 @@
 | 
			
		||||
    input[type="search"],
 | 
			
		||||
    input[type="number"] {
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
		font-size: .8em;
 | 
			
		||||
		height: $btnToolbarH;
 | 
			
		||||
		margin-bottom: 1px;
 | 
			
		||||
		position: relative;
 | 
			
		||||
		&.sm {
 | 
			
		||||
			width: $btnToolbarH;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<!-- look at action-button for example -->
 | 
			
		||||
<span class="t-filter l-filter"
 | 
			
		||||
<span class="t-filter l-filter s-filter"
 | 
			
		||||
      ng-controller="GetterSetterController">
 | 
			
		||||
	<input type="search"
 | 
			
		||||
           class="t-filter-input"
 | 
			
		||||
 
 | 
			
		||||
@@ -117,8 +117,6 @@ define(
 | 
			
		||||
 | 
			
		||||
                // Apply styles to child elements
 | 
			
		||||
                function updateChildren(children) {
 | 
			
		||||
                    position = userWidthPreference || position;
 | 
			
		||||
 | 
			
		||||
                    // Pick out correct elements to update, flowing from
 | 
			
		||||
                    // selected anchor edge.
 | 
			
		||||
                    var first = children.eq(anchor.reversed ? 2 : 0),
 | 
			
		||||
@@ -128,7 +126,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                    splitterSize = getSize(splitter[0]);
 | 
			
		||||
                    first.css(anchor.edge, "0px");
 | 
			
		||||
                    first.css(anchor.dimension, position + 'px');
 | 
			
		||||
                    first.css(anchor.dimension, (userWidthPreference || position) + 'px');
 | 
			
		||||
 | 
			
		||||
                    // Get actual size (to obey min-width etc.)
 | 
			
		||||
                    firstSize = getSize(first[0]);
 | 
			
		||||
@@ -137,8 +135,8 @@ define(
 | 
			
		||||
                    splitter.css(anchor.opposite, "auto");
 | 
			
		||||
 | 
			
		||||
                    last.css(anchor.edge, firstSize + splitterSize + 'px');
 | 
			
		||||
                    last.css(anchor.opposite, '0px');
 | 
			
		||||
                    position = firstSize;
 | 
			
		||||
                    last.css(anchor.opposite, "0px");
 | 
			
		||||
                    position = firstSize + splitterSize;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Update positioning of contained elements
 | 
			
		||||
@@ -175,19 +173,17 @@ define(
 | 
			
		||||
                            positionParsed.assign($scope, position);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return position;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function setUserWidthPreference(value) {
 | 
			
		||||
                    if (alias) {
 | 
			
		||||
                        userWidthPreference = value;
 | 
			
		||||
                    }
 | 
			
		||||
                    userWidthPreference = value - splitterSize;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function persistToLocalStorage(value) {
 | 
			
		||||
                    if (alias) {
 | 
			
		||||
                        $window.localStorage.setItem(alias, value);
 | 
			
		||||
                        userWidthPreference = value - splitterSize;
 | 
			
		||||
                        $window.localStorage.setItem(alias, userWidthPreference);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -229,13 +225,13 @@ define(
 | 
			
		||||
                    anchor: function () {
 | 
			
		||||
                        return anchor;
 | 
			
		||||
                    },
 | 
			
		||||
                    position: function (newPosition) {
 | 
			
		||||
                        if (arguments.length === 0) {
 | 
			
		||||
                    position: function (value) {
 | 
			
		||||
                        if (arguments.length > 0) {
 | 
			
		||||
                            setUserWidthPreference(value);
 | 
			
		||||
                            return getSetPosition(value);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            return getSetPosition();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        setUserWidthPreference(newPosition);
 | 
			
		||||
                        return getSetPosition(newPosition);
 | 
			
		||||
                    },
 | 
			
		||||
                    startResizing: function () {
 | 
			
		||||
                        toggleClass('resizing');
 | 
			
		||||
 
 | 
			
		||||
@@ -57,10 +57,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                        // Update the position of this splitter
 | 
			
		||||
                        newPosition =  initialPosition + pixelDelta;
 | 
			
		||||
 | 
			
		||||
                        if (initialPosition !== newPosition) {
 | 
			
		||||
                            mctSplitPane.position(newPosition);
 | 
			
		||||
                        }
 | 
			
		||||
                        mctSplitPane.position(newPosition);
 | 
			
		||||
                    },
 | 
			
		||||
                    // Grab the event when the user is done moving
 | 
			
		||||
                    // the splitter and pass it on
 | 
			
		||||
 
 | 
			
		||||
@@ -140,7 +140,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                it("exposes its splitter's initial position", function () {
 | 
			
		||||
                    expect(controller.position()).toEqual(
 | 
			
		||||
                        mockFirstPane[0].offsetWidth
 | 
			
		||||
                        mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
@@ -168,7 +168,7 @@ define(
 | 
			
		||||
                    controller.position(testValue);
 | 
			
		||||
                    expect(mockFirstPane.css).toHaveBeenCalledWith(
 | 
			
		||||
                        'width',
 | 
			
		||||
                        (testValue) + 'px'
 | 
			
		||||
                        (testValue - mockSplitter[0].offsetWidth) + 'px'
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
@@ -200,11 +200,11 @@ define(
 | 
			
		||||
                    mockFirstPane[0].offsetWidth += 100;
 | 
			
		||||
                    // Should not reflect the change yet
 | 
			
		||||
                    expect(controller.position()).not.toEqual(
 | 
			
		||||
                        mockFirstPane[0].offsetWidth
 | 
			
		||||
                        mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
 | 
			
		||||
                    );
 | 
			
		||||
                    mockInterval.mostRecentCall.args[0]();
 | 
			
		||||
                    expect(controller.position()).toEqual(
 | 
			
		||||
                        mockFirstPane[0].offsetWidth
 | 
			
		||||
                        mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
@@ -216,7 +216,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                it("saves user preference to localStorage when user is done resizing", function () {
 | 
			
		||||
                    controller.endResizing(100);
 | 
			
		||||
                    expect(Number(mockWindow.localStorage.getItem('mctSplitPane-rightSide'))).toEqual(100);
 | 
			
		||||
                    expect(Number(mockWindow.localStorage.getItem('mctSplitPane-rightSide'))).toEqual(100 - mockSplitter[0].offsetWidth);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
@@ -53,15 +53,9 @@ $timeControllerToiLineColor: #00c2ff;
 | 
			
		||||
$timeControllerToiLineColorHov: #fff;
 | 
			
		||||
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
 | 
			
		||||
 | 
			
		||||
// Foundation Colors
 | 
			
		||||
// General Colors
 | 
			
		||||
$colorAlt1: #ffc700;
 | 
			
		||||
$colorAlert: #ff3c00;
 | 
			
		||||
$colorWarningHi: #cc0000;
 | 
			
		||||
$colorWarningLo: #ff9900;
 | 
			
		||||
$colorDiagnostic: #a4b442;
 | 
			
		||||
$colorCommand: #3693bd;
 | 
			
		||||
$colorInfo: #2294a2;
 | 
			
		||||
$colorOk: #33cc33;
 | 
			
		||||
$colorIconLink: #49dedb;
 | 
			
		||||
$colorPausedBg: #c56f01;
 | 
			
		||||
$colorPausedFg: #fff;
 | 
			
		||||
@@ -90,8 +84,8 @@ $colorCreateMenuText: $colorMenuFg;
 | 
			
		||||
// Form colors
 | 
			
		||||
$colorCheck: $colorKey;
 | 
			
		||||
$colorFormRequired: $colorAlt1;
 | 
			
		||||
$colorFormValid: $colorOk;
 | 
			
		||||
$colorFormError: $colorWarningHi;
 | 
			
		||||
$colorFormValid: #33cc33;
 | 
			
		||||
$colorFormError: #990000;
 | 
			
		||||
$colorFormInvalid: #ff3300;
 | 
			
		||||
$colorFormFieldErrorBg: $colorFormError;
 | 
			
		||||
$colorFormFieldErrorFg: rgba(#fff, 0.6);
 | 
			
		||||
@@ -115,8 +109,8 @@ $colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
 | 
			
		||||
// Status colors, mainly used for messaging and item ancillary symbols
 | 
			
		||||
$colorStatusFg: #ccc;
 | 
			
		||||
$colorStatusDefault: #ccc;
 | 
			
		||||
$colorStatusInfo: $colorInfo;
 | 
			
		||||
$colorStatusAlert: $colorAlert;
 | 
			
		||||
$colorStatusInfo: #62ba72;
 | 
			
		||||
$colorStatusAlert: #ffa66d;
 | 
			
		||||
$colorStatusError: #d4585c;
 | 
			
		||||
$colorStatusAvailable: $colorKey;
 | 
			
		||||
$colorStatusBtnBg: $colorBtnBg;
 | 
			
		||||
@@ -131,14 +125,14 @@ $animPausedPulseDur: 500ms;
 | 
			
		||||
$colorSelectBg: $colorBtnBg;
 | 
			
		||||
$colorSelectFg: $colorBtnFg;
 | 
			
		||||
 | 
			
		||||
// Limits, status and staleness colors
 | 
			
		||||
// Limits and staleness colors
 | 
			
		||||
$colorTelemFresh: pullForward($colorBodyFg, 20%);
 | 
			
		||||
$colorTelemStale: pushBack($colorBodyFg, 20%);
 | 
			
		||||
$styleTelemStale: italic;
 | 
			
		||||
$colorLimitYellowBg: rgba($colorWarningLo, 0.3);
 | 
			
		||||
$colorLimitYellowIc: $colorWarningLo;
 | 
			
		||||
$colorLimitRedBg: rgba($colorWarningHi, 0.3);
 | 
			
		||||
$colorLimitRedIc: $colorWarningHi;
 | 
			
		||||
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
 | 
			
		||||
$colorLimitYellowIc: #ffaa00;
 | 
			
		||||
$colorLimitRedBg: rgba(red, 0.3);
 | 
			
		||||
$colorLimitRedIc: red;
 | 
			
		||||
 | 
			
		||||
// Bubble colors
 | 
			
		||||
$colorInfoBubbleBg: #ddd;
 | 
			
		||||
@@ -201,15 +195,13 @@ $shdwItemTreeIcon: 0.6;
 | 
			
		||||
$colorThumbHoverBg: $colorItemTreeHoverBg;
 | 
			
		||||
 | 
			
		||||
// Scrollbar
 | 
			
		||||
$scrollbarTrackSize: 7px;
 | 
			
		||||
$scrollbarTrackShdw: rgba(#000, 0.5) 0 1px 5px;
 | 
			
		||||
$scrollbarTrackColorBg: transparent; //rgba(#000, 0.4);
 | 
			
		||||
$scrollbarTrackSize: 10px;
 | 
			
		||||
$scrollbarTrackShdw: rgba(#000, 0.7) 0 1px 5px;
 | 
			
		||||
$scrollbarTrackColorBg: rgba(#000, 0.4);
 | 
			
		||||
$scrollbarThumbColor: pullForward($colorBodyBg, 10%);
 | 
			
		||||
$scrollbarThumbColorHov: pullForward($scrollbarThumbColor, 2%);
 | 
			
		||||
$scrollbarThumbColorOverlay: pullForward($colorOvrBg, 10%);
 | 
			
		||||
$scrollbarThumbColorOverlayHov: pullForward($scrollbarThumbColorOverlay, 2%);
 | 
			
		||||
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 20%);
 | 
			
		||||
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
 | 
			
		||||
 | 
			
		||||
// Splitter
 | 
			
		||||
// All splitterD* values MUST both be either odd or even numbers
 | 
			
		||||
@@ -243,6 +235,12 @@ $colorCalCellSelectedBg: $colorItemTreeSelectedBg;
 | 
			
		||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
 | 
			
		||||
$colorCalCellInMonthBg: pushBack($colorMenuBg, 5%);
 | 
			
		||||
 | 
			
		||||
// Palettes
 | 
			
		||||
$colorPaletteFg: pullForward($colorMenuBg, 30%);
 | 
			
		||||
$colorPaletteSelected: #fff;
 | 
			
		||||
$shdwPaletteFg: black 0 0 2px;
 | 
			
		||||
$shdwPaletteSelected: inset 0 0 0 1px #000;
 | 
			
		||||
 | 
			
		||||
// About Screen
 | 
			
		||||
$colorAboutLink: #84b3ff;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,10 +13,3 @@
 | 
			
		||||
    // For dark interfaces, darker things move back - opposite for light interfaces
 | 
			
		||||
    @return darken($c, $p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@function bgFg($c) {
 | 
			
		||||
    // Given a single color, return valid background and foreground versions of that color
 | 
			
		||||
    $bg: darken($c, 20%);
 | 
			
		||||
    $fg: lighten($c, 20%);
 | 
			
		||||
    @return $bg, $fg;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -53,15 +53,9 @@ $timeControllerToiLineColor: $colorBodyFg;
 | 
			
		||||
$timeControllerToiLineColorHov: #0052b5;
 | 
			
		||||
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
 | 
			
		||||
 | 
			
		||||
// Foundation Colors
 | 
			
		||||
// General Colors
 | 
			
		||||
$colorAlt1: #776ba2;
 | 
			
		||||
$colorAlert: #ff3c00;
 | 
			
		||||
$colorWarningHi: #990000;
 | 
			
		||||
$colorWarningLo: #ff9900;
 | 
			
		||||
$colorDiagnostic: #a4b442;
 | 
			
		||||
$colorCommand: #3693bd;
 | 
			
		||||
$colorInfo: #2294a2;
 | 
			
		||||
$colorOk: #33cc33;
 | 
			
		||||
$colorIconLink: #49dedb;
 | 
			
		||||
$colorPausedBg: #ff9900;
 | 
			
		||||
$colorPausedFg: #fff;
 | 
			
		||||
@@ -90,8 +84,8 @@ $colorCreateMenuText: $colorBodyFg;
 | 
			
		||||
// Form colors
 | 
			
		||||
$colorCheck: $colorKey;
 | 
			
		||||
$colorFormRequired: $colorKey;
 | 
			
		||||
$colorFormValid: $colorOk;
 | 
			
		||||
$colorFormError: $colorWarningHi;
 | 
			
		||||
$colorFormValid: #33cc33;
 | 
			
		||||
$colorFormError: #990000;
 | 
			
		||||
$colorFormInvalid: #ff2200;
 | 
			
		||||
$colorFormFieldErrorBg: $colorFormError;
 | 
			
		||||
$colorFormFieldErrorFg: rgba(#fff, 0.6);
 | 
			
		||||
@@ -113,7 +107,7 @@ $colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
 | 
			
		||||
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
 | 
			
		||||
 | 
			
		||||
// Status colors, mainly used for messaging and item ancillary symbols
 | 
			
		||||
$colorStatusFg: #999;
 | 
			
		||||
$colorStatusFg: #fff;
 | 
			
		||||
$colorStatusDefault: #ccc;
 | 
			
		||||
$colorStatusInfo: #60ba7b;
 | 
			
		||||
$colorStatusAlert: #ffb66c;
 | 
			
		||||
@@ -201,15 +195,13 @@ $shdwItemTreeIcon: none;
 | 
			
		||||
$colorThumbHoverBg: $colorItemTreeHoverBg;
 | 
			
		||||
 | 
			
		||||
// Scrollbar
 | 
			
		||||
$scrollbarTrackSize: 7px;
 | 
			
		||||
$scrollbarTrackSize: 10px;
 | 
			
		||||
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
 | 
			
		||||
$scrollbarTrackColorBg: rgba(#000, 0.2);
 | 
			
		||||
$scrollbarThumbColor: darken($colorBodyBg, 50%);
 | 
			
		||||
$scrollbarThumbColorHov: $colorKey;
 | 
			
		||||
$scrollbarThumbColorOverlay: darken($colorOvrBg, 50%);
 | 
			
		||||
$scrollbarThumbColorOverlayHov: $scrollbarThumbColorHov;
 | 
			
		||||
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 10%);
 | 
			
		||||
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
 | 
			
		||||
 | 
			
		||||
// Splitter
 | 
			
		||||
// All splitterD* values MUST both be either odd or even numbers
 | 
			
		||||
@@ -243,6 +235,12 @@ $colorCalCellSelectedBg: $colorItemTreeSelectedBg;
 | 
			
		||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
 | 
			
		||||
$colorCalCellInMonthBg: pullForward($colorMenuBg, 5%);
 | 
			
		||||
 | 
			
		||||
// Palettes
 | 
			
		||||
$colorPaletteFg: pullForward($colorMenuBg, 30%);
 | 
			
		||||
$colorPaletteSelected: #333;
 | 
			
		||||
$shdwPaletteFg: none;
 | 
			
		||||
$shdwPaletteSelected: inset 0 0 0 1px #fff;
 | 
			
		||||
 | 
			
		||||
// About Screen
 | 
			
		||||
$colorAboutLink: #84b3ff;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,3 @@
 | 
			
		||||
    // For dark interfaces, darker things move back - opposite for light interfaces
 | 
			
		||||
    @return lighten($c, $p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@function bgFg($c) {
 | 
			
		||||
    // Given a single color, return valid background and foreground versions of that color
 | 
			
		||||
    $bg: darken($c, 20%);
 | 
			
		||||
    $fg: lighten($c, 20%);
 | 
			
		||||
    @return $bg, $fg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -94,6 +94,31 @@ define([
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "extensions": {
 | 
			
		||||
            "versions": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Version",
 | 
			
		||||
                    "value": "@@version",
 | 
			
		||||
                    "priority": 999
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Built",
 | 
			
		||||
                    "value": "@@timestamp",
 | 
			
		||||
                    "description": "The date on which this version of the client was built.",
 | 
			
		||||
                    "priority": 990
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Revision",
 | 
			
		||||
                    "value": "@@revision",
 | 
			
		||||
                    "description": "A unique revision identifier for the client sources.",
 | 
			
		||||
                    "priority": 995
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Branch",
 | 
			
		||||
                    "value": "@@branch",
 | 
			
		||||
                    "description": "The name of the branch that was used during the build.",
 | 
			
		||||
                    "priority": 994
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "components": [
 | 
			
		||||
                {
 | 
			
		||||
                    "provides": "objectService",
 | 
			
		||||
 
 | 
			
		||||
@@ -65,20 +65,6 @@ define(['csv'], function (CSV) {
 | 
			
		||||
        this.saveAs(blob, filename);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Export an object as a JSON file. Triggers a download using the function
 | 
			
		||||
     * provided when the ExportService was instantiated.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} obj an object to be exported as JSON
 | 
			
		||||
     * @param {ExportOptions} [options] additional parameters for the file
 | 
			
		||||
     *        export
 | 
			
		||||
     */
 | 
			
		||||
    ExportService.prototype.exportJSON = function (obj, options) {
 | 
			
		||||
        var filename = (options && options.filename) || "test-export.json";
 | 
			
		||||
        var jsonText = JSON.stringify(obj);
 | 
			
		||||
        var blob = new Blob([jsonText], {type: "application/json"});
 | 
			
		||||
        this.saveAs(blob, filename);
 | 
			
		||||
    };
 | 
			
		||||
    /**
 | 
			
		||||
     * Additional parameters for file export.
 | 
			
		||||
     * @typedef ExportOptions
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
$ueTimeConductorH: (25px, 16px, 20px); // Heights for Ticks, Data Visualization, Controls elements
 | 
			
		||||
$ueTimeConductorRtH: (25px, 3px, 20px); // Heights for elements in Real-time mode
 | 
			
		||||
$timeCondInputTimeSysDefW: 165px; // Default width for datetime value inputs
 | 
			
		||||
$timeCondInputDeltaDefW: 65px; // Default width for delta value inputs, typically 00:00:00
 | 
			
		||||
$timeCondInputDeltaDefW: 60px; // Default width for delta value inputs, typically 00:00:00
 | 
			
		||||
$timeCondTOIIconD: 12px; // height and width of icon used for TOI indicator
 | 
			
		||||
$timeCondTOIValOffset: 0px;
 | 
			
		||||
$ticksBlockerFadeW: 50px;
 | 
			
		||||
 
 | 
			
		||||
@@ -162,6 +162,9 @@
 | 
			
		||||
            .l-time-conductor-inputs {
 | 
			
		||||
                pointer-events: auto;
 | 
			
		||||
            }
 | 
			
		||||
            input[type="text"] {
 | 
			
		||||
                @include trans-prop-nice(padding, 250ms);
 | 
			
		||||
            }
 | 
			
		||||
            .time-range-input input[type="text"] {
 | 
			
		||||
                width: $timeCondInputTimeSysDefW;
 | 
			
		||||
            }
 | 
			
		||||
@@ -287,6 +290,18 @@
 | 
			
		||||
 | 
			
		||||
        .l-time-conductor-inputs-holder {
 | 
			
		||||
            .l-time-range-input-w {
 | 
			
		||||
                input[type="text"]:not(.error) {
 | 
			
		||||
                    background: transparent;
 | 
			
		||||
                    box-shadow: none;
 | 
			
		||||
                    border-radius: 0;
 | 
			
		||||
                    padding-left: 0;
 | 
			
		||||
                    padding-right: 0;
 | 
			
		||||
                    &:hover,
 | 
			
		||||
                    &:focus {
 | 
			
		||||
                        @include nice-input();
 | 
			
		||||
                        padding: $inputTextP;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .icon-calendar {
 | 
			
		||||
                    display: none;
 | 
			
		||||
                }
 | 
			
		||||
@@ -294,11 +309,8 @@
 | 
			
		||||
                    display: none;
 | 
			
		||||
                }
 | 
			
		||||
                &.end-date {
 | 
			
		||||
                    // Displays the current time
 | 
			
		||||
                    pointer-events: none;
 | 
			
		||||
                    input[type="text"] {
 | 
			
		||||
                        background: none;
 | 
			
		||||
                        box-shadow: none;
 | 
			
		||||
                        color: pullForward($colorTimeCondKeyBg, 5%);
 | 
			
		||||
                        margin-right: $interiorMargin;
 | 
			
		||||
                        tab-index: -1;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,8 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div class="w-menu">
 | 
			
		||||
    <div class="col menu-items">
 | 
			
		||||
<div class="contents">
 | 
			
		||||
    <div class="pane left menu-items">
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li ng-repeat="metadata in ngModel.options"
 | 
			
		||||
                ng-click="ngModel.select(metadata)">
 | 
			
		||||
@@ -32,15 +32,13 @@
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col menu-item-description">
 | 
			
		||||
    <div class="pane right menu-item-description">
 | 
			
		||||
        <div class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssClass}}"></div>
 | 
			
		||||
        <div class="w-title-desc">
 | 
			
		||||
            <div class="desc-area title">
 | 
			
		||||
                {{ngModel.activeMetadata.name}}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="desc-area description">
 | 
			
		||||
                {{ngModel.activeMetadata.description}}
 | 
			
		||||
            </div>
 | 
			
		||||
        <div class="desc-area title">
 | 
			
		||||
            {{ngModel.activeMetadata.name}}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="desc-area description">
 | 
			
		||||
            {{ngModel.activeMetadata.description}}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
         ng-click="modeController.toggle()">
 | 
			
		||||
		<span class="title-label">{{ngModel.selected.name}}</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="menu super-menu mini l-mode-selector-menu"
 | 
			
		||||
    <div class="menu super-menu mini mode-selector-menu"
 | 
			
		||||
         ng-show="modeController.isActive()">
 | 
			
		||||
        <mct-include key="'mode-menu'"
 | 
			
		||||
                     ng-model="ngModel">
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
                                         ng-model="boundsModel"
 | 
			
		||||
                                         ng-blur="tcController.setOffsetsFromView(boundsModel)"
 | 
			
		||||
                                         field="'startOffset'"
 | 
			
		||||
                                         class="s-input-inline hrs-min-input">
 | 
			
		||||
                                         class="hrs-min-input">
 | 
			
		||||
                            </mct-control>
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </span>
 | 
			
		||||
@@ -71,7 +71,7 @@
 | 
			
		||||
                                         ng-model="boundsModel"
 | 
			
		||||
                                         ng-blur="tcController.setOffsetsFromView(boundsModel)"
 | 
			
		||||
                                         field="'endOffset'"
 | 
			
		||||
                                         class="s-input-inline hrs-min-input">
 | 
			
		||||
                                         class="hrs-min-input">
 | 
			
		||||
                            </mct-control>
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </span>
 | 
			
		||||
 
 | 
			
		||||
@@ -201,7 +201,7 @@ define(
 | 
			
		||||
            var options = [{
 | 
			
		||||
                key: 'fixed',
 | 
			
		||||
                name: 'Fixed Timespan Mode',
 | 
			
		||||
                description: 'Query and explore data that falls between two fixed datetimes.',
 | 
			
		||||
                description: 'Query and explore data that falls between two fixed datetimes',
 | 
			
		||||
                cssClass: 'icon-calendar'
 | 
			
		||||
            }];
 | 
			
		||||
            var clocks = {};
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,14 @@ define([
 | 
			
		||||
                                        "description": "Set border color",
 | 
			
		||||
                                        "control": "color"
 | 
			
		||||
                                    },
 | 
			
		||||
                                    {
 | 
			
		||||
                                        "property": "color",
 | 
			
		||||
                                        "cssClass": "icon-T",
 | 
			
		||||
                                        "title": "Text color",
 | 
			
		||||
                                        "description": "Set text color",
 | 
			
		||||
                                        "mandatory": true,
 | 
			
		||||
                                        "control": "color"
 | 
			
		||||
                                    },
 | 
			
		||||
                                    {
 | 
			
		||||
                                        "property": "url",
 | 
			
		||||
                                        "cssClass": "icon-image",
 | 
			
		||||
@@ -137,27 +145,6 @@ define([
 | 
			
		||||
                                    }
 | 
			
		||||
                                ]
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "items": [
 | 
			
		||||
                                    {
 | 
			
		||||
                                        "property": "color",
 | 
			
		||||
                                        "cssClass": "icon-T",
 | 
			
		||||
                                        "title": "Text color",
 | 
			
		||||
                                        "description": "Set text color",
 | 
			
		||||
                                        "mandatory": true,
 | 
			
		||||
                                        "control": "color"
 | 
			
		||||
                                    },
 | 
			
		||||
                                    {
 | 
			
		||||
                                        "property": "size",
 | 
			
		||||
                                        "title": "Text size",
 | 
			
		||||
                                        "description": "Set text size",
 | 
			
		||||
                                        "control": "select",
 | 
			
		||||
                                        "options": [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96].map(function (size) {
 | 
			
		||||
                                            return { "name": size + " px", "value": size + "px" };
 | 
			
		||||
                                        })
 | 
			
		||||
                                    }
 | 
			
		||||
                                ]
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "items": [
 | 
			
		||||
                                    {
 | 
			
		||||
@@ -225,7 +212,11 @@ define([
 | 
			
		||||
                                        "control": "numberfield",
 | 
			
		||||
                                        "description": "Resize object width",
 | 
			
		||||
                                        "min": "1"
 | 
			
		||||
                                    },
 | 
			
		||||
                                    }
 | 
			
		||||
                                ]
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "items": [
 | 
			
		||||
                                    {
 | 
			
		||||
                                        "property": "useGrid",
 | 
			
		||||
                                        "name": "Snap to Grid",
 | 
			
		||||
 
 | 
			
		||||
@@ -19,10 +19,10 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<a class="l-hyperlink s-hyperlink" ng-controller="HyperlinkController as hyperlink" href="{{domainObject.getModel().url}}"
 | 
			
		||||
<a class="s-hyperlink" ng-controller="HyperlinkController as hyperlink" href="{{domainObject.getModel().url}}"
 | 
			
		||||
   ng-attr-target="{{hyperlink.openNewTab() ? '_blank' : undefined}}"
 | 
			
		||||
   ng-class="{
 | 
			
		||||
       's-button': hyperlink.isButton()
 | 
			
		||||
   }">
 | 
			
		||||
    <span class="label">{{domainObject.getModel().displayText}}</span>
 | 
			
		||||
    <div class="label">{{domainObject.getModel().displayText}}</div>
 | 
			
		||||
</a>
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,14 @@ define([
 | 
			
		||||
    "./src/controllers/ImageryController",
 | 
			
		||||
    "./src/directives/MCTBackgroundImage",
 | 
			
		||||
    "text!./res/templates/imagery.html",
 | 
			
		||||
    "text!./res/templates/imageryTimeline.html",
 | 
			
		||||
    'legacyRegistry'
 | 
			
		||||
], function (
 | 
			
		||||
    ImageryViewPolicy,
 | 
			
		||||
    ImageryController,
 | 
			
		||||
    MCTBackgroundImage,
 | 
			
		||||
    imageryTemplate,
 | 
			
		||||
    imageryTimelineTemplate,
 | 
			
		||||
    legacyRegistry
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
@@ -48,6 +50,17 @@ define([
 | 
			
		||||
                        "telemetry"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "editable": false
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Historical Imagery",
 | 
			
		||||
                    "key": "historical-imagery",
 | 
			
		||||
                    "cssClass": "icon-image",
 | 
			
		||||
                    "template": imageryTimelineTemplate,
 | 
			
		||||
                    "priority": "preferred",
 | 
			
		||||
                    "needs": [
 | 
			
		||||
                        "telemetry"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "editable": false
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "policies": [
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
<div class="t-imagery" ng-controller="ImageryController as imagery">
 | 
			
		||||
    <mct-split-pane class='abs' anchor="bottom" alias="imagery">
 | 
			
		||||
    <div class="split-pane-component l-image-main-wrapper l-flex-col"
 | 
			
		||||
    <div class="l-image-main-wrapper l-flex-col"
 | 
			
		||||
        ng-mouseenter="showLocalControls = true;"
 | 
			
		||||
        ng-mouseleave="showLocalControls = false;">
 | 
			
		||||
        <div class="l-local-controls s-local-controls s-wrapper-transluc l-flex-row"
 | 
			
		||||
@@ -33,12 +32,12 @@
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="l-image-main-controlbar flex-elem l-flex-row">
 | 
			
		||||
            <div class="l-datetime-w flex-elem grows">
 | 
			
		||||
            <div class="left flex-elem grows">
 | 
			
		||||
                <a class="s-button show-thumbs sm hidden icon-thumbs-strip"
 | 
			
		||||
                    ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a>
 | 
			
		||||
                <span class="l-time">{{imagery.getTime()}}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="l-controls-w flex-elem">
 | 
			
		||||
            <div class="right flex-elem">
 | 
			
		||||
                <a class="s-button pause-play"
 | 
			
		||||
                    ng-click="imagery.paused(!imagery.paused())"
 | 
			
		||||
                    ng-class="{ paused: imagery.paused() }"></a>
 | 
			
		||||
@@ -56,14 +55,4 @@
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <mct-splitter></mct-splitter>
 | 
			
		||||
    <div class="split-pane-component l-image-thumbs-wrapper">
 | 
			
		||||
        <div class="l-image-thumb-item" ng-class="{selected: image.selected}" ng-repeat="image in imageHistory track by $index" 
 | 
			
		||||
            ng-click="imagery.setSelectedImage(image)"  ng-init="imagery.scrollToBottom()">
 | 
			
		||||
            <img class="l-thumb" 
 | 
			
		||||
                ng-src={{imagery.getImageUrl(image)}}>
 | 
			
		||||
            <div class="l-time">{{imagery.getTime(image)}}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    </mct-split-pane>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
 | 
			
		||||
<div class="l-image-thumbs-wrapper" ng-controller="ImageryController as imagery">
 | 
			
		||||
	<div class="l-image-thumb-item" ng-repeat="image in imageHistory track by $index">
 | 
			
		||||
		<img class="l-thumb" ng-init="imagery.scrollToRight()"
 | 
			
		||||
			ng-src={{imagery.getImageUrl(image)}} >
 | 
			
		||||
			<div class="l-time">{{imagery.getTime(image)}}</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -48,8 +48,9 @@ define(
 | 
			
		||||
            this.zone = "";
 | 
			
		||||
            this.imageUrl = "";
 | 
			
		||||
            this.requestCount = 0;
 | 
			
		||||
            this.scrollable = $(".l-image-thumbs-wrapper");
 | 
			
		||||
            this.scrollable = $(element[0]);
 | 
			
		||||
            this.autoScroll = openmct.time.clock() ? true : false;
 | 
			
		||||
 | 
			
		||||
            this.$scope.imageHistory = [];
 | 
			
		||||
            this.$scope.filters = {
 | 
			
		||||
                brightness: 100,
 | 
			
		||||
@@ -62,7 +63,6 @@ define(
 | 
			
		||||
            this.updateHistory = this.updateHistory.bind(this);
 | 
			
		||||
            this.onBoundsChange = this.onBoundsChange.bind(this);
 | 
			
		||||
            this.onScroll = this.onScroll.bind(this);
 | 
			
		||||
            this.setSelectedImage = this.setSelectedImage.bind(this);
 | 
			
		||||
 | 
			
		||||
            this.subscribe(this.$scope.domainObject);
 | 
			
		||||
 | 
			
		||||
@@ -80,10 +80,10 @@ define(
 | 
			
		||||
                    var metadata = this.openmct
 | 
			
		||||
                        .telemetry
 | 
			
		||||
                        .getMetadata(this.domainObject);
 | 
			
		||||
                    this.timeKey = this.openmct.time.timeSystem().key;
 | 
			
		||||
                    var timeKey = this.openmct.time.timeSystem().key;
 | 
			
		||||
                    this.timeFormat = this.openmct
 | 
			
		||||
                        .telemetry
 | 
			
		||||
                        .getValueFormatter(metadata.value(this.timeKey));
 | 
			
		||||
                        .getValueFormatter(metadata.value(timeKey));
 | 
			
		||||
                    this.imageFormat = this.openmct
 | 
			
		||||
                        .telemetry
 | 
			
		||||
                        .getValueFormatter(metadata.valuesForHints(['image'])[0]);
 | 
			
		||||
@@ -161,7 +161,7 @@ define(
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Updates displayable values to match those of the most
 | 
			
		||||
         * recently received datum.
 | 
			
		||||
         * recently recieved datum.
 | 
			
		||||
         * @param {object} [datum] the datum
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
@@ -170,6 +170,7 @@ define(
 | 
			
		||||
                this.nextDatum = datum;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.time = this.timeFormat.format(datum);
 | 
			
		||||
            this.imageUrl = this.imageFormat.format(datum);
 | 
			
		||||
 | 
			
		||||
@@ -184,7 +185,8 @@ define(
 | 
			
		||||
        ImageryController.prototype.updateHistory = function (datum) {
 | 
			
		||||
            if (this.$scope.imageHistory.length === 0 ||
 | 
			
		||||
                !_.isEqual(this.$scope.imageHistory.slice(-1)[0], datum)) {
 | 
			
		||||
                var index = _.sortedIndex(this.$scope.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
 | 
			
		||||
 | 
			
		||||
                var index = _.sortedIndex(this.$scope.imageHistory, datum, 'utc');
 | 
			
		||||
                this.$scope.imageHistory.splice(index, 0, datum);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
@@ -194,12 +196,8 @@ define(
 | 
			
		||||
 | 
			
		||||
        ImageryController.prototype.onScroll = function (event) {
 | 
			
		||||
            this.$window.requestAnimationFrame(function () {
 | 
			
		||||
                var thumbnailWrapperHeight = this.scrollable[0].offsetHeight;
 | 
			
		||||
                var thumbnailWrapperWidth = this.scrollable[0].offsetWidth;
 | 
			
		||||
                if (this.scrollable[0].scrollLeft <
 | 
			
		||||
                    (this.scrollable[0].scrollWidth - this.scrollable[0].clientWidth) - (thumbnailWrapperWidth) ||
 | 
			
		||||
                    this.scrollable[0].scrollTop <
 | 
			
		||||
                    (this.scrollable[0].scrollHeight - this.scrollable[0].clientHeight) - (thumbnailWrapperHeight)) {
 | 
			
		||||
                    (this.scrollable[0].scrollWidth - this.scrollable[0].clientWidth) - 20) {
 | 
			
		||||
                    this.autoScroll = false;
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.autoScroll = true;
 | 
			
		||||
@@ -207,16 +205,12 @@ define(
 | 
			
		||||
            }.bind(this));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Force history imagery div to scroll to bottom.
 | 
			
		||||
         */
 | 
			
		||||
        ImageryController.prototype.scrollToBottom = function () {
 | 
			
		||||
        ImageryController.prototype.scrollToRight = function () {
 | 
			
		||||
            if (this.autoScroll) {
 | 
			
		||||
                this.scrollable[0].scrollTop = this.scrollable[0].scrollHeight;
 | 
			
		||||
                this.scrollable[0].scrollLeft = this.scrollable[0].scrollWidth;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the time portion (hours, minutes, seconds) of the
 | 
			
		||||
         * timestamp associated with the incoming image telemetry
 | 
			
		||||
@@ -249,38 +243,16 @@ define(
 | 
			
		||||
         * @returns {boolean} the current state
 | 
			
		||||
         */
 | 
			
		||||
        ImageryController.prototype.paused = function (state) {
 | 
			
		||||
            if (arguments.length > 0 && state !== this.isPaused) {
 | 
			
		||||
                this.unselectAllImages();
 | 
			
		||||
                this.isPaused = state;
 | 
			
		||||
                if (this.nextDatum) {
 | 
			
		||||
                    this.updateValues(this.nextDatum);
 | 
			
		||||
                    delete this.nextDatum;
 | 
			
		||||
                if (arguments.length > 0 && state !== this.isPaused) {
 | 
			
		||||
                    this.isPaused = state;
 | 
			
		||||
                    if (this.nextDatum) {
 | 
			
		||||
                        this.updateValues(this.nextDatum);
 | 
			
		||||
                        delete this.nextDatum;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                this.autoScroll = true;
 | 
			
		||||
            }
 | 
			
		||||
            return this.isPaused;
 | 
			
		||||
        };
 | 
			
		||||
                return this.isPaused;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the selected image on the state for the large imagery div to use.
 | 
			
		||||
         * @param {object} [image] the image object to get url from.
 | 
			
		||||
         */
 | 
			
		||||
        ImageryController.prototype.setSelectedImage = function (image) {
 | 
			
		||||
            this.imageUrl = this.getImageUrl(image);
 | 
			
		||||
            this.time = this.getTime(image);
 | 
			
		||||
            this.paused(true);
 | 
			
		||||
            this.unselectAllImages();
 | 
			
		||||
            image.selected = true;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Loop through the history imagery data to set all images to unselected.
 | 
			
		||||
         */
 | 
			
		||||
        ImageryController.prototype.unselectAllImages = function () {
 | 
			
		||||
            for (var i = 0; i < this.$scope.imageHistory.length; i++) {
 | 
			
		||||
                this.$scope.imageHistory[i].selected = false;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        return ImageryController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -226,28 +226,6 @@ define(
 | 
			
		||||
                    expect(controller.updateHistory(mockDatum)).toBe(false);
 | 
			
		||||
                    expect(controller.updateHistory(mockDatum)).toBe(false);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                describe("user clicks on imagery thumbnail", function () {
 | 
			
		||||
                    var mockDatum = { utc: 1434600258123, url: 'some/url', selected: false};
 | 
			
		||||
 | 
			
		||||
                    it("pauses and adds selected class to imagery thumbnail", function () {
 | 
			
		||||
                        controller.setSelectedImage(mockDatum);
 | 
			
		||||
                        expect(controller.paused()).toBeTruthy();
 | 
			
		||||
                        expect(mockDatum.selected).toBeTruthy();
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it("unselects previously selected image", function () {
 | 
			
		||||
                        $scope.imageHistory = [{ utc: 1434600258123, url: 'some/url', selected: true}];
 | 
			
		||||
                        controller.unselectAllImages();
 | 
			
		||||
                        expect($scope.imageHistory[0].selected).toBeFalsy();
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it("updates larger image url and time", function () {
 | 
			
		||||
                        controller.setSelectedImage(mockDatum);
 | 
			
		||||
                        expect(controller.getImageUrl()).toEqual(controller.getImageUrl(mockDatum));
 | 
			
		||||
                        expect(controller.getTime()).toEqual(controller.timeFormat.format(mockDatum.utc));
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("initially shows an empty string for date/time", function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
-->
 | 
			
		||||
<div
 | 
			
		||||
    class="l-fixed-position-text l-telemetry"
 | 
			
		||||
    ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color(), 'font-size': ngModel.size() }"
 | 
			
		||||
    ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color() }"
 | 
			
		||||
    >
 | 
			
		||||
    <span
 | 
			
		||||
        class="l-elem l-value l-obj-val-format"
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
-->
 | 
			
		||||
<div
 | 
			
		||||
	class="l-fixed-position-text l-static-text"
 | 
			
		||||
	ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color(), 'font-size': ngModel.size() }"
 | 
			
		||||
	ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color() }"
 | 
			
		||||
	>
 | 
			
		||||
    {{ngModel.element.text}}
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
    <div class="abs object-browse-bar l-flex-row">
 | 
			
		||||
        <div class="left flex-elem l-flex-row grows">
 | 
			
		||||
            <mct-representation
 | 
			
		||||
                    key="'object-header-frame'"
 | 
			
		||||
                    key="'object-header'"
 | 
			
		||||
                    mct-object="domainObject"
 | 
			
		||||
                    class="l-flex-row flex-elem object-header grows">
 | 
			
		||||
            </mct-representation>
 | 
			
		||||
 
 | 
			
		||||
@@ -58,19 +58,6 @@ define(
 | 
			
		||||
             */
 | 
			
		||||
            proxy.text = new AccessorMutator(element, 'text');
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Get and/or set the text size of this element.
 | 
			
		||||
             *
 | 
			
		||||
             * @param {string} [size] the new text size (if setting)
 | 
			
		||||
             * @returns {string} the text size
 | 
			
		||||
             * @memberof platform/features/layout.TextProxy#
 | 
			
		||||
             */
 | 
			
		||||
            proxy.size = new AccessorMutator(element, 'size');
 | 
			
		||||
 | 
			
		||||
            if (proxy.size() === undefined) {
 | 
			
		||||
                proxy.size("13px");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return proxy;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,8 +35,7 @@ define(
 | 
			
		||||
                    y: 2,
 | 
			
		||||
                    width: 42,
 | 
			
		||||
                    height: 24,
 | 
			
		||||
                    fill: "transparent",
 | 
			
		||||
                    size: "20px"
 | 
			
		||||
                    fill: "transparent"
 | 
			
		||||
                };
 | 
			
		||||
                testElements = [{}, {}, testElement, {}];
 | 
			
		||||
                proxy = new TextProxy(
 | 
			
		||||
@@ -51,20 +50,6 @@ define(
 | 
			
		||||
                expect(proxy.fill('#FFF')).toEqual('#FFF');
 | 
			
		||||
                expect(proxy.fill()).toEqual('#FFF');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides getter/setter for text size", function () {
 | 
			
		||||
                expect(proxy.size()).toEqual('20px');
 | 
			
		||||
                expect(proxy.size('12px')).toEqual('12px');
 | 
			
		||||
                expect(proxy.size()).toEqual('12px');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("defaults to 13px for unspecified text size", function () {
 | 
			
		||||
                testElement = {x: 1, y: 2};
 | 
			
		||||
                proxy = new TextProxy(testElement, 0, [testElement]);
 | 
			
		||||
 | 
			
		||||
                expect(proxy.size()).toEqual('13px');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -118,10 +118,7 @@ define([
 | 
			
		||||
            "policies": [
 | 
			
		||||
                {
 | 
			
		||||
                    "category": "view",
 | 
			
		||||
                    "implementation": PlotViewPolicy,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "openmct"
 | 
			
		||||
                    ]
 | 
			
		||||
                    "implementation": PlotViewPolicy
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "representations": [
 | 
			
		||||
 
 | 
			
		||||
@@ -30,32 +30,30 @@ define(
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         */
 | 
			
		||||
        function PlotViewPolicy(openmct) {
 | 
			
		||||
            this.openmct = openmct;
 | 
			
		||||
        function PlotViewPolicy() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PlotViewPolicy.prototype.hasNumericTelemetry = function (domainObject) {
 | 
			
		||||
            var adaptedObject = domainObject.useCapability('adapter');
 | 
			
		||||
        function hasNumericTelemetry(domainObject) {
 | 
			
		||||
            var telemetry = domainObject &&
 | 
			
		||||
                    domainObject.getCapability('telemetry'),
 | 
			
		||||
                metadata = telemetry ? telemetry.getMetadata() : {},
 | 
			
		||||
                ranges = metadata.ranges || [];
 | 
			
		||||
 | 
			
		||||
            if (!adaptedObject.telemetry) {
 | 
			
		||||
                return domainObject.hasCapability('delegation') &&
 | 
			
		||||
                    domainObject.getCapability('delegation')
 | 
			
		||||
                            .doesDelegateCapability('telemetry');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var metadata = this.openmct.telemetry.getMetadata(adaptedObject);
 | 
			
		||||
            var rangeValues = metadata.valuesForHints(['range']);
 | 
			
		||||
            if (rangeValues.length === 0) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return !rangeValues.every(function (value) {
 | 
			
		||||
                return value.format === 'string';
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
            // Generally, we want to allow Plot for telemetry-providing
 | 
			
		||||
            // objects (most telemetry is plottable.) We only want to
 | 
			
		||||
            // suppress this for telemetry which only has explicitly
 | 
			
		||||
            // non-numeric values.
 | 
			
		||||
            return ranges.length === 0 || ranges.some(function (range) {
 | 
			
		||||
                    // Assume format is numeric if it is undefined
 | 
			
		||||
                    // (numeric telemetry is the common case)
 | 
			
		||||
                    return range.format === undefined ||
 | 
			
		||||
                        range.format === 'number';
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PlotViewPolicy.prototype.allow = function (view, domainObject) {
 | 
			
		||||
            if (view.key === 'plot') {
 | 
			
		||||
                return this.hasNumericTelemetry(domainObject);
 | 
			
		||||
                return hasNumericTelemetry(domainObject);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,97 +27,51 @@ define(
 | 
			
		||||
        describe("Plot view policy", function () {
 | 
			
		||||
            var testView,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                testAdaptedObject,
 | 
			
		||||
                openmct,
 | 
			
		||||
                telemetryMetadata,
 | 
			
		||||
                mockTelemetry,
 | 
			
		||||
                testMetadata,
 | 
			
		||||
                policy;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testView = { key: "plot" };
 | 
			
		||||
                testAdaptedObject = { telemetry: {} };
 | 
			
		||||
                testMetadata = {};
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    'domainObject',
 | 
			
		||||
                    ['useCapability', 'hasCapability', 'getCapability']
 | 
			
		||||
                    ['getId', 'getModel', 'getCapability']
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject.useCapability.andReturn(testAdaptedObject);
 | 
			
		||||
                openmct = {
 | 
			
		||||
                    telemetry: jasmine.createSpyObj('telemetryAPI', [
 | 
			
		||||
                        'getMetadata'
 | 
			
		||||
                    ])
 | 
			
		||||
                };
 | 
			
		||||
                telemetryMetadata = jasmine.createSpyObj('telemetryMetadata', [
 | 
			
		||||
                    'valuesForHints'
 | 
			
		||||
                ]);
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([]);
 | 
			
		||||
                openmct.telemetry.getMetadata.andReturn(telemetryMetadata);
 | 
			
		||||
                policy = new PlotViewPolicy(openmct);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('fetches metadata from telem api', function () {
 | 
			
		||||
                policy.allow(testView, mockDomainObject);
 | 
			
		||||
                expect(mockDomainObject.useCapability)
 | 
			
		||||
                    .toHaveBeenCalledWith('adapter');
 | 
			
		||||
                expect(openmct.telemetry.getMetadata)
 | 
			
		||||
                    .toHaveBeenCalledWith(testAdaptedObject);
 | 
			
		||||
                expect(telemetryMetadata.valuesForHints)
 | 
			
		||||
                    .toHaveBeenCalledWith(['range']);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns false if no ranges exist', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true if any ranges exist', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([{}]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns false if all ranges are strings', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([{
 | 
			
		||||
                    format: 'string'
 | 
			
		||||
                }, {
 | 
			
		||||
                    format: 'string'
 | 
			
		||||
                }]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true if only some ranges are strings', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([{
 | 
			
		||||
                    format: 'string'
 | 
			
		||||
                }, {}]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true for telemetry delegators', function () {
 | 
			
		||||
                delete testAdaptedObject.telemetry;
 | 
			
		||||
                mockDomainObject.hasCapability.andCallFake(function (c) {
 | 
			
		||||
                    return c === 'delegation';
 | 
			
		||||
                mockTelemetry = jasmine.createSpyObj(
 | 
			
		||||
                    'telemetry',
 | 
			
		||||
                    ['getMetadata']
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject.getCapability.andCallFake(function (c) {
 | 
			
		||||
                    return c === 'telemetry' ? mockTelemetry : undefined;
 | 
			
		||||
                });
 | 
			
		||||
                mockDomainObject.getCapability.andReturn(
 | 
			
		||||
                    jasmine.createSpyObj('delegation', [
 | 
			
		||||
                        'doesDelegateCapability'
 | 
			
		||||
                    ])
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject.getCapability('delegation')
 | 
			
		||||
                    .doesDelegateCapability.andCallFake(function (c) {
 | 
			
		||||
                        return c === 'telemetry';
 | 
			
		||||
                    });
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
                expect(openmct.telemetry.getMetadata).not.toHaveBeenCalled();
 | 
			
		||||
                mockTelemetry.getMetadata.andReturn(testMetadata);
 | 
			
		||||
 | 
			
		||||
                policy = new PlotViewPolicy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true for non-telemetry non-delegators', function () {
 | 
			
		||||
                delete testAdaptedObject.telemetry;
 | 
			
		||||
                mockDomainObject.hasCapability.andReturn(false);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(false);
 | 
			
		||||
            it("allows the imagery view for domain objects with numeric telemetry", function () {
 | 
			
		||||
                testMetadata.ranges = [{ key: "foo", format: "number" }];
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows the imagery view for domain objects with unspecified telemetry", function () {
 | 
			
		||||
                testMetadata.ranges = [{ key: "foo"  }];
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("disallows the imagery view for domain objects without image telemetry", function () {
 | 
			
		||||
                testMetadata.ranges = [{ key: "foo", format: "somethingElse" }];
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows other views", function () {
 | 
			
		||||
                testView.key = "somethingElse";
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
                testMetadata.ranges = [{ key: "foo", format: "somethingElse" }];
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,6 @@ define([
 | 
			
		||||
    "./src/MCTForm",
 | 
			
		||||
    "./src/MCTToolbar",
 | 
			
		||||
    "./src/MCTControl",
 | 
			
		||||
    "./src/MCTFileInput",
 | 
			
		||||
    "./src/FileInputService",
 | 
			
		||||
    "./src/controllers/AutocompleteController",
 | 
			
		||||
    "./src/controllers/DateTimeController",
 | 
			
		||||
    "./src/controllers/CompositeController",
 | 
			
		||||
@@ -44,14 +42,11 @@ define([
 | 
			
		||||
    "text!./res/templates/controls/menu-button.html",
 | 
			
		||||
    "text!./res/templates/controls/dialog.html",
 | 
			
		||||
    "text!./res/templates/controls/radio.html",
 | 
			
		||||
    "text!./res/templates/controls/file-input.html",
 | 
			
		||||
    'legacyRegistry'
 | 
			
		||||
], function (
 | 
			
		||||
    MCTForm,
 | 
			
		||||
    MCTToolbar,
 | 
			
		||||
    MCTControl,
 | 
			
		||||
    MCTFileInput,
 | 
			
		||||
    FileInputService,
 | 
			
		||||
    AutocompleteController,
 | 
			
		||||
    DateTimeController,
 | 
			
		||||
    CompositeController,
 | 
			
		||||
@@ -70,7 +65,6 @@ define([
 | 
			
		||||
    menuButtonTemplate,
 | 
			
		||||
    dialogTemplate,
 | 
			
		||||
    radioTemplate,
 | 
			
		||||
    fileInputTemplate,
 | 
			
		||||
    legacyRegistry
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
@@ -94,13 +88,6 @@ define([
 | 
			
		||||
                        "templateLinker",
 | 
			
		||||
                        "controls[]"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "mctFileInput",
 | 
			
		||||
                    "implementation": MCTFileInput,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "fileInputService"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "controls": [
 | 
			
		||||
@@ -155,10 +142,6 @@ define([
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "dialog-button",
 | 
			
		||||
                    "template": dialogTemplate
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "file-input",
 | 
			
		||||
                    "template": fileInputTemplate
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "controllers": [
 | 
			
		||||
@@ -193,14 +176,6 @@ define([
 | 
			
		||||
                        "dialogService"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "components": [
 | 
			
		||||
                {
 | 
			
		||||
                    "provides": "fileInputService",
 | 
			
		||||
                    "type": "provider",
 | 
			
		||||
                    "implementation": FileInputService
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -24,21 +24,22 @@
 | 
			
		||||
 | 
			
		||||
    <span class="l-click-area" ng-click="toggle.toggle()"></span>
 | 
			
		||||
    <span class="color-swatch"
 | 
			
		||||
          ng-class="{'no-selection':ngModel[field] === 'transparent'}"
 | 
			
		||||
          ng-style="{
 | 
			
		||||
             background: ngModel[field]
 | 
			
		||||
             'background-color': ngModel[field]
 | 
			
		||||
         }">
 | 
			
		||||
    </span>
 | 
			
		||||
    <span class="title-label" ng-if="structure.text">
 | 
			
		||||
        {{structure.text}}
 | 
			
		||||
    </span>
 | 
			
		||||
 | 
			
		||||
    <div class="menu l-color-palette"
 | 
			
		||||
    <div class="menu l-palette l-color-palette"
 | 
			
		||||
        ng-controller="ColorController as colors"
 | 
			
		||||
        ng-show="toggle.isActive()">
 | 
			
		||||
        <div
 | 
			
		||||
            class="l-palette-row l-option-row"
 | 
			
		||||
            ng-if="!structure.mandatory">
 | 
			
		||||
            <div class="l-palette-item s-palette-item {{ngModel[field] === 'transparent' ? 'icon-check' : '' }}"
 | 
			
		||||
            <div class="l-palette-item s-palette-item no-selection {{ngModel[field] === 'transparent' ? 'selected' : '' }}"
 | 
			
		||||
                ng-click="ngModel[field] = 'transparent'">
 | 
			
		||||
            </div>
 | 
			
		||||
            <span class="l-palette-item-label">None</span>
 | 
			
		||||
@@ -46,7 +47,7 @@
 | 
			
		||||
        <div
 | 
			
		||||
            class="l-palette-row"
 | 
			
		||||
            ng-repeat="group in colors.groups()">
 | 
			
		||||
            <div class="l-palette-item s-palette-item {{ngModel[field] === color ? 'icon-check' : '' }}"
 | 
			
		||||
            <div class="l-palette-item s-palette-item {{ngModel[field] === color ? 'selected' : '' }}"
 | 
			
		||||
                ng-repeat="color in group"
 | 
			
		||||
                ng-style="{ background: color }"
 | 
			
		||||
                ng-click="ngModel[field] = color">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<a class="s-button {{structure.cssClass}}"
 | 
			
		||||
   ng-model="ngModel[field]"
 | 
			
		||||
   ng-class="{ labeled: structure.text }"
 | 
			
		||||
   mct-file-input>
 | 
			
		||||
    <span class="title-label" ng-if="structure.text">
 | 
			
		||||
        {{structure.text}}
 | 
			
		||||
    </span>
 | 
			
		||||
</a>
 | 
			
		||||
@@ -1,90 +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(["zepto"], function ($) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The FileInputService provides an interface for triggering a file input.
 | 
			
		||||
     *
 | 
			
		||||
     * @constructor
 | 
			
		||||
     * @memberof platform/forms
 | 
			
		||||
     */
 | 
			
		||||
    function FileInputService() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates, triggers, and destroys a file picker element and returns a
 | 
			
		||||
     * promise for an object containing the chosen file's name and contents.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns {Promise} promise for an object containing file meta-data
 | 
			
		||||
     */
 | 
			
		||||
    FileInputService.prototype.getInput = function () {
 | 
			
		||||
        var input = this.newInput();
 | 
			
		||||
        var read = this.readFile;
 | 
			
		||||
        var fileInfo = {};
 | 
			
		||||
        var file;
 | 
			
		||||
 | 
			
		||||
        return new Promise(function (resolve, reject) {
 | 
			
		||||
            input.trigger("click");
 | 
			
		||||
            input.on('change', function (event) {
 | 
			
		||||
                file = this.files[0];
 | 
			
		||||
                input.remove();
 | 
			
		||||
                if (file) {
 | 
			
		||||
                    read(file)
 | 
			
		||||
                        .then(function (contents) {
 | 
			
		||||
                            fileInfo.name = file.name;
 | 
			
		||||
                            fileInfo.body = contents;
 | 
			
		||||
                            resolve(fileInfo);
 | 
			
		||||
                        }, function () {
 | 
			
		||||
                            reject("File read error");
 | 
			
		||||
                        });
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    FileInputService.prototype.readFile = function (file) {
 | 
			
		||||
        var fileReader = new FileReader();
 | 
			
		||||
 | 
			
		||||
        return new Promise(function (resolve, reject) {
 | 
			
		||||
            fileReader.onload = function (event) {
 | 
			
		||||
                resolve(event.target.result);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            fileReader.onerror = function () {
 | 
			
		||||
                return reject(event.target.result);
 | 
			
		||||
            };
 | 
			
		||||
            fileReader.readAsText(file);
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    FileInputService.prototype.newInput  = function () {
 | 
			
		||||
        var input = $(document.createElement('input'));
 | 
			
		||||
        input.attr("type", "file");
 | 
			
		||||
        input.css("display", "none");
 | 
			
		||||
        $('body').append(input);
 | 
			
		||||
        return input;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return FileInputService;
 | 
			
		||||
});
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['zepto'],
 | 
			
		||||
    function ($) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The mct-file-input handles behavior of the file input form control.
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @memberof platform/forms
 | 
			
		||||
         */
 | 
			
		||||
        function MCTFileInput(fileInputService) {
 | 
			
		||||
 | 
			
		||||
            function link(scope, element, attrs, control) {
 | 
			
		||||
 | 
			
		||||
                function setText(fileName) {
 | 
			
		||||
                    scope.structure.text = fileName.length > 20 ?
 | 
			
		||||
                    fileName.substr(0, 20) + "..." :
 | 
			
		||||
                    fileName;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function handleClick() {
 | 
			
		||||
                    fileInputService.getInput().then(function (result) {
 | 
			
		||||
                        setText(result.name);
 | 
			
		||||
                        scope.ngModel[scope.field] = result;
 | 
			
		||||
                        control.$setValidity("file-input", true);
 | 
			
		||||
                    }, function () {
 | 
			
		||||
                        setText('Select File');
 | 
			
		||||
                        control.$setValidity("file-input", false);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                control.$setValidity("file-input", false);
 | 
			
		||||
                element.on('click', handleClick);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                restrict: "A",
 | 
			
		||||
                require: "^form",
 | 
			
		||||
                link: link
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return MCTFileInput;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,74 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/FileInputService"],
 | 
			
		||||
    function (FileInputService) {
 | 
			
		||||
 | 
			
		||||
        describe("The FileInputService", function () {
 | 
			
		||||
            var fileInputService,
 | 
			
		||||
                mockInput;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                fileInputService = new FileInputService();
 | 
			
		||||
                mockInput = jasmine.createSpyObj('input',
 | 
			
		||||
                    [
 | 
			
		||||
                        'on',
 | 
			
		||||
                        'trigger',
 | 
			
		||||
                        'remove'
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                mockInput.on.andCallFake(function (event, changeHandler) {
 | 
			
		||||
                    changeHandler.apply(mockInput);
 | 
			
		||||
                });
 | 
			
		||||
                spyOn(fileInputService, "newInput").andReturn(
 | 
			
		||||
                    mockInput
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("can read a file", function () {
 | 
			
		||||
                mockInput.files = [new File(["file content"], "file name")];
 | 
			
		||||
                fileInputService.getInput().then(function (result) {
 | 
			
		||||
                    expect(result.name).toBe("file name");
 | 
			
		||||
                    expect(result.body).toBe("file content");
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                expect(mockInput.trigger).toHaveBeenCalledWith('click');
 | 
			
		||||
                expect(mockInput.remove).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("catches file read errors", function () {
 | 
			
		||||
                mockInput.files = ["GARBAGE"];
 | 
			
		||||
                fileInputService.getInput().then(
 | 
			
		||||
                    function (result) {},
 | 
			
		||||
                    function (err) {
 | 
			
		||||
                        expect(err).toBe("File read error");
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                expect(mockInput.trigger).toHaveBeenCalledWith('click');
 | 
			
		||||
                expect(mockInput.remove).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,98 +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(
 | 
			
		||||
    ["../src/MCTFileInput"],
 | 
			
		||||
    function (MCTFileInput) {
 | 
			
		||||
 | 
			
		||||
        describe("The mct-file-input directive", function () {
 | 
			
		||||
 | 
			
		||||
            var mockScope,
 | 
			
		||||
                mockFileInputService,
 | 
			
		||||
                mctFileInput,
 | 
			
		||||
                element,
 | 
			
		||||
                attrs,
 | 
			
		||||
                control;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                attrs = [];
 | 
			
		||||
                control = jasmine.createSpyObj('control', ['$setValidity']);
 | 
			
		||||
                element = jasmine.createSpyObj('element', ['on', 'trigger']);
 | 
			
		||||
                mockFileInputService = jasmine.createSpyObj('fileInputService',
 | 
			
		||||
                    ['getInput']
 | 
			
		||||
                );
 | 
			
		||||
                mockScope = jasmine.createSpyObj(
 | 
			
		||||
                        '$scope',
 | 
			
		||||
                        ['$watch']
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockScope.structure = {text: 'Select File'};
 | 
			
		||||
                mockScope.field = "file-input";
 | 
			
		||||
                mockScope.ngModel = {"file-input" : undefined};
 | 
			
		||||
 | 
			
		||||
                element.on.andCallFake(function (event, clickHandler) {
 | 
			
		||||
                    clickHandler();
 | 
			
		||||
                });
 | 
			
		||||
                mockFileInputService.getInput.andReturn(
 | 
			
		||||
                    Promise.resolve({name: "file-name", body: "file-body"})
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mctFileInput = new MCTFileInput(mockFileInputService);
 | 
			
		||||
 | 
			
		||||
                // Need to wait for mock promise
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    mctFileInput.link(mockScope, element, attrs, control);
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "File selection should have beeen simulated");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("is restricted to attributes", function () {
 | 
			
		||||
                expect(mctFileInput.restrict).toEqual("A");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("changes button text to match file name", function () {
 | 
			
		||||
                expect(element.on).toHaveBeenCalledWith(
 | 
			
		||||
                    'click',
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
                expect(mockScope.structure.text).toEqual("file-name");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("validates control on file selection", function () {
 | 
			
		||||
                expect(control.$setValidity.callCount).toBe(2);
 | 
			
		||||
                expect(control.$setValidity.argsForCall[0]).toEqual(
 | 
			
		||||
                    ['file-input', false]
 | 
			
		||||
                );
 | 
			
		||||
                expect(control.$setValidity.argsForCall[1]).toEqual(
 | 
			
		||||
                    ['file-input', true]
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,76 +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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    "./src/actions/ExportAsJSONAction",
 | 
			
		||||
    "./src/actions/ImportAsJSONAction"
 | 
			
		||||
], function (
 | 
			
		||||
    ExportAsJSONAction,
 | 
			
		||||
    ImportAsJSONAction
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    return function ImportExportPlugin() {
 | 
			
		||||
        return function (openmct) {
 | 
			
		||||
            ExportAsJSONAction.appliesTo = function (context) {
 | 
			
		||||
                return openmct.$injector.get('policyService')
 | 
			
		||||
                  .allow("creation", context.domainObject.getCapability("type")
 | 
			
		||||
                );
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            openmct.legacyRegistry.register("platform/import-export", {
 | 
			
		||||
                "name": "Import-export plugin",
 | 
			
		||||
                "description": "Allows importing / exporting of domain objects as JSON.",
 | 
			
		||||
                "extensions": {
 | 
			
		||||
                    "actions": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "export.JSON",
 | 
			
		||||
                            "name": "Export as JSON",
 | 
			
		||||
                            "implementation": ExportAsJSONAction,
 | 
			
		||||
                            "category": "contextual",
 | 
			
		||||
                            "cssClass": "icon-export",
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                "exportService",
 | 
			
		||||
                                "policyService",
 | 
			
		||||
                                "identifierService"
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "import.JSON",
 | 
			
		||||
                            "name": "Import from JSON",
 | 
			
		||||
                            "implementation": ImportAsJSONAction,
 | 
			
		||||
                            "category": "contextual",
 | 
			
		||||
                            "cssClass": "icon-import",
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                 "exportService",
 | 
			
		||||
                                 "identifierService",
 | 
			
		||||
                                 "dialogService",
 | 
			
		||||
                                 "openmct"
 | 
			
		||||
                            ]
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            openmct.legacyRegistry.enable('platform/import-export');
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
@@ -1,162 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([], function () {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The ExportAsJSONAction is available from context menus and allows a user
 | 
			
		||||
     * to export any creatable domain object as a JSON file.
 | 
			
		||||
     *
 | 
			
		||||
     * @implements {Action}
 | 
			
		||||
     * @constructor
 | 
			
		||||
     * @memberof platform/import-export
 | 
			
		||||
     */
 | 
			
		||||
    function ExportAsJSONAction(
 | 
			
		||||
        exportService,
 | 
			
		||||
        policyService,
 | 
			
		||||
        identifierService,
 | 
			
		||||
        context
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        this.root = {};
 | 
			
		||||
        this.tree = {};
 | 
			
		||||
        this.calls = 0;
 | 
			
		||||
        this.context = context;
 | 
			
		||||
        this.externalIdentifiers = [];
 | 
			
		||||
        this.exportService = exportService;
 | 
			
		||||
        this.policyService = policyService;
 | 
			
		||||
        this.identifierService = identifierService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ExportAsJSONAction.prototype.perform = function () {
 | 
			
		||||
        this.root = this.context.domainObject;
 | 
			
		||||
        this.tree[this.root.getId()] = this.root.getModel();
 | 
			
		||||
        this.saveAs = function (completedTree) {
 | 
			
		||||
            this.exportService.exportJSON(
 | 
			
		||||
                completedTree,
 | 
			
		||||
                {filename: this.root.getModel().name + '.json'}
 | 
			
		||||
            );
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this.write(this.root);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Traverses object hierarchy and populates tree object with models and
 | 
			
		||||
     * identifiers.
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     * @param {Object} parent
 | 
			
		||||
     */
 | 
			
		||||
    ExportAsJSONAction.prototype.write = function (parent) {
 | 
			
		||||
 | 
			
		||||
        this.calls++;
 | 
			
		||||
        if (parent.hasCapability('composition')) {
 | 
			
		||||
            parent.useCapability('composition')
 | 
			
		||||
                .then(function (children) {
 | 
			
		||||
                    children.forEach(function (child, index) {
 | 
			
		||||
                        // Only export if object is creatable
 | 
			
		||||
                        if (this.isCreatable(child)) {
 | 
			
		||||
                            // Prevents infinite export of self-contained objs
 | 
			
		||||
                            if (!this.tree.hasOwnProperty(child.getId())) {
 | 
			
		||||
                                // If object is a link to something absent from
 | 
			
		||||
                                // tree, generate new id and treat as new object
 | 
			
		||||
                                if (this.isExternal(child, parent)) {
 | 
			
		||||
                                    this.rewriteLink(child, parent);
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    this.tree[child.getId()] = child.getModel();
 | 
			
		||||
                                }
 | 
			
		||||
                                this.write(child);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }.bind(this));
 | 
			
		||||
                    this.calls--;
 | 
			
		||||
                    if (this.calls === 0) {
 | 
			
		||||
                        this.saveAs(this.wrapTree());
 | 
			
		||||
                    }
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
        } else {
 | 
			
		||||
            this.calls--;
 | 
			
		||||
            if (this.calls === 0) {
 | 
			
		||||
                this.saveAs(this.wrapTree());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Exports an externally linked object as an entirely new object in the
 | 
			
		||||
     * case where the original is not present in the exported tree.
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    ExportAsJSONAction.prototype.rewriteLink = function (child, parent) {
 | 
			
		||||
        this.externalIdentifiers.push(child.getId());
 | 
			
		||||
        var parentModel = parent.getModel();
 | 
			
		||||
        var childModel = child.getModel();
 | 
			
		||||
        var index = parentModel.composition.indexOf(child.getId());
 | 
			
		||||
        var newModel = this.copyModel(childModel);
 | 
			
		||||
        var newId = this.identifierService.generate();
 | 
			
		||||
 | 
			
		||||
        newModel.location = parent.getId();
 | 
			
		||||
        this.tree[newId] = newModel;
 | 
			
		||||
        this.tree[parent.getId()] = this.copyModel(parentModel);
 | 
			
		||||
        this.tree[parent.getId()].composition[index] = newId;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ExportAsJSONAction.prototype.copyModel = function (model) {
 | 
			
		||||
        var jsonString = JSON.stringify(model);
 | 
			
		||||
        return JSON.parse(jsonString);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ExportAsJSONAction.prototype.isExternal = function (child, parent) {
 | 
			
		||||
        if (child.getModel().location !== parent.getId() &&
 | 
			
		||||
            !Object.keys(this.tree).includes(child.getModel().location) &&
 | 
			
		||||
            child.getId() !== this.root.getId() ||
 | 
			
		||||
            this.externalIdentifiers.includes(child.getId())) {
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Wraps root object for identification on reimport and wraps entire
 | 
			
		||||
     * exported JSON construct for validation.
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    ExportAsJSONAction.prototype.wrapTree = function () {
 | 
			
		||||
        return {
 | 
			
		||||
            "openmct": this.tree,
 | 
			
		||||
            "rootId": this.root.getId()
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ExportAsJSONAction.prototype.isCreatable = function (domainObject) {
 | 
			
		||||
        return this.policyService.allow(
 | 
			
		||||
            "creation",
 | 
			
		||||
            domainObject.getCapability("type")
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return ExportAsJSONAction;
 | 
			
		||||
});
 | 
			
		||||
@@ -1,175 +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(['zepto'], function ($) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The ImportAsJSONAction is available from context menus and allows a user
 | 
			
		||||
     * to import a previously exported domain object into any domain object
 | 
			
		||||
     * that has the composition capability.
 | 
			
		||||
     *
 | 
			
		||||
     * @implements {Action}
 | 
			
		||||
     * @constructor
 | 
			
		||||
     * @memberof platform/import-export
 | 
			
		||||
     */
 | 
			
		||||
    function ImportAsJSONAction(
 | 
			
		||||
        exportService,
 | 
			
		||||
        identifierService,
 | 
			
		||||
        dialogService,
 | 
			
		||||
        openmct,
 | 
			
		||||
        context
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        this.openmct = openmct;
 | 
			
		||||
        this.context = context;
 | 
			
		||||
        this.exportService = exportService;
 | 
			
		||||
        this.dialogService = dialogService;
 | 
			
		||||
        this.identifierService = identifierService;
 | 
			
		||||
        this.instantiate = openmct.$injector.get("instantiate");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.perform = function () {
 | 
			
		||||
        this.dialogService.getUserInput(this.getFormModel(), {})
 | 
			
		||||
            .then(function (form) {
 | 
			
		||||
                var objectTree = form.selectFile.body;
 | 
			
		||||
                if (this.validateJSON(objectTree)) {
 | 
			
		||||
                    this.importObjectTree(JSON.parse(objectTree));
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.displayError();
 | 
			
		||||
                }
 | 
			
		||||
            }.bind(this));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.importObjectTree = function (objTree) {
 | 
			
		||||
        var parent = this.context.domainObject;
 | 
			
		||||
        var tree = this.generateNewIdentifiers(objTree);
 | 
			
		||||
        var rootId = tree.rootId;
 | 
			
		||||
        var rootObj = this.instantiate(tree.openmct[rootId], rootId);
 | 
			
		||||
 | 
			
		||||
        // Instantiate all objects in tree with their newly genereated ids,
 | 
			
		||||
        // adding each to its rightful parent's composition
 | 
			
		||||
        rootObj.getCapability("location").setPrimaryLocation(parent.getId());
 | 
			
		||||
        this.deepInstantiate(rootObj, tree.openmct, []);
 | 
			
		||||
        parent.getCapability("composition").add(rootObj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {
 | 
			
		||||
        // Traverses object tree, instantiates all domain object w/ new IDs and
 | 
			
		||||
        // adds to parent's composition
 | 
			
		||||
        if (parent.hasCapability("composition")) {
 | 
			
		||||
            var parentModel = parent.getModel();
 | 
			
		||||
            var newObj;
 | 
			
		||||
 | 
			
		||||
            seen.push(parent.getId());
 | 
			
		||||
            parentModel.composition.forEach(function (childId, index) {
 | 
			
		||||
                if (!tree[childId] || seen.includes(childId)) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                newObj = this.instantiate(tree[childId], childId);
 | 
			
		||||
                parent.getCapability("composition").add(newObj);
 | 
			
		||||
                newObj.getCapability("location")
 | 
			
		||||
                    .setPrimaryLocation(tree[childId].location);
 | 
			
		||||
                this.deepInstantiate(newObj, tree, seen);
 | 
			
		||||
            }, this);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.generateNewIdentifiers = function (tree) {
 | 
			
		||||
        // For each domain object in the file, generate new ID, replace in tree
 | 
			
		||||
        Object.keys(tree.openmct).forEach(function (domainObjectId) {
 | 
			
		||||
            var newId = this.identifierService.generate();
 | 
			
		||||
            tree = this.rewriteId(domainObjectId, newId, tree);
 | 
			
		||||
        }, this);
 | 
			
		||||
        return tree;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rewrites all instances of a given id in the tree with a newly generated
 | 
			
		||||
     * replacement to prevent collision.
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    ImportAsJSONAction.prototype.rewriteId = function (oldID, newID, tree) {
 | 
			
		||||
        tree = JSON.stringify(tree).replace(new RegExp(oldID, 'g'), newID);
 | 
			
		||||
        return JSON.parse(tree);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.getFormModel = function () {
 | 
			
		||||
        return {
 | 
			
		||||
            name: "Import as JSON",
 | 
			
		||||
            sections: [
 | 
			
		||||
                {
 | 
			
		||||
                    name: "Import A File",
 | 
			
		||||
                    rows: [
 | 
			
		||||
                        {
 | 
			
		||||
                            name: 'Select File',
 | 
			
		||||
                            key: 'selectFile',
 | 
			
		||||
                            control: 'file-input',
 | 
			
		||||
                            required: true,
 | 
			
		||||
                            text: 'Select File'
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.validateJSON = function (jsonString) {
 | 
			
		||||
        var json;
 | 
			
		||||
        try {
 | 
			
		||||
            json = JSON.parse(jsonString);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (!json.openmct || !json.rootId) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.displayError = function () {
 | 
			
		||||
        var dialog,
 | 
			
		||||
        model = {
 | 
			
		||||
            title: "Invalid File",
 | 
			
		||||
            actionText:  "The selected file was either invalid JSON or was " +
 | 
			
		||||
                "not formatted properly for import into Open MCT.",
 | 
			
		||||
            severity: "error",
 | 
			
		||||
            options: [
 | 
			
		||||
                {
 | 
			
		||||
                    label: "Ok",
 | 
			
		||||
                    callback: function () {
 | 
			
		||||
                        dialog.dismiss();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        };
 | 
			
		||||
        dialog = this.dialogService.showBlockingMessage(model);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.appliesTo = function (context) {
 | 
			
		||||
        return context.domainObject !== undefined &&
 | 
			
		||||
            context.domainObject.hasCapability("composition");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return ImportAsJSONAction;
 | 
			
		||||
});
 | 
			
		||||
@@ -1,266 +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(
 | 
			
		||||
    [
 | 
			
		||||
        "../../src/actions/ExportAsJSONAction",
 | 
			
		||||
        "../../../entanglement/test/DomainObjectFactory"
 | 
			
		||||
    ],
 | 
			
		||||
    function (ExportAsJSONAction, domainObjectFactory) {
 | 
			
		||||
 | 
			
		||||
        describe("The export JSON action", function () {
 | 
			
		||||
 | 
			
		||||
            var context,
 | 
			
		||||
                action,
 | 
			
		||||
                exportService,
 | 
			
		||||
                identifierService,
 | 
			
		||||
                policyService,
 | 
			
		||||
                mockType,
 | 
			
		||||
                exportedTree;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                exportService = jasmine.createSpyObj('exportService',
 | 
			
		||||
                ['exportJSON']);
 | 
			
		||||
                identifierService = jasmine.createSpyObj('identifierService',
 | 
			
		||||
                            ['generate']);
 | 
			
		||||
                policyService = jasmine.createSpyObj('policyService',
 | 
			
		||||
                    ['allow']);
 | 
			
		||||
                mockType =
 | 
			
		||||
                    jasmine.createSpyObj('type', ['hasFeature']);
 | 
			
		||||
 | 
			
		||||
                mockType.hasFeature.andCallFake(function (feature) {
 | 
			
		||||
                    return feature === 'creation';
 | 
			
		||||
                });
 | 
			
		||||
                context = {};
 | 
			
		||||
                context.domainObject = domainObjectFactory(
 | 
			
		||||
                    {
 | 
			
		||||
                        name: 'test',
 | 
			
		||||
                        id: 'someID',
 | 
			
		||||
                        capabilities: {type: mockType}
 | 
			
		||||
                    });
 | 
			
		||||
                identifierService.generate.andReturn('brandNewId');
 | 
			
		||||
                exportService.exportJSON.andCallFake(function (tree, options) {
 | 
			
		||||
                    exportedTree = tree;
 | 
			
		||||
                });
 | 
			
		||||
                policyService.allow.andCallFake(function (capability, type) {
 | 
			
		||||
                    return type.hasFeature(capability);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                action = new ExportAsJSONAction(exportService, policyService,
 | 
			
		||||
                        identifierService, context);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("initializes happily", function () {
 | 
			
		||||
                expect(action).toBeDefined();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("doesn't export non-creatable objects in tree", function () {
 | 
			
		||||
                var nonCreatableType = {
 | 
			
		||||
                    hasFeature :
 | 
			
		||||
                        function (feature) {
 | 
			
		||||
                            return feature !== 'creation';
 | 
			
		||||
                        }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                var parentComposition =
 | 
			
		||||
                    jasmine.createSpyObj('parentComposition', ['invoke']);
 | 
			
		||||
 | 
			
		||||
                var parent = domainObjectFactory({
 | 
			
		||||
                    name: 'parent',
 | 
			
		||||
                    model: { name: 'parent', location: 'ROOT'},
 | 
			
		||||
                    id: 'parentId',
 | 
			
		||||
                    capabilities: {
 | 
			
		||||
                        composition: parentComposition,
 | 
			
		||||
                        type: mockType
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                var child = domainObjectFactory({
 | 
			
		||||
                    name: 'child',
 | 
			
		||||
                    model: { name: 'child', location: 'parentId' },
 | 
			
		||||
                    id: 'childId',
 | 
			
		||||
                    capabilities: {
 | 
			
		||||
                        type: nonCreatableType
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                parentComposition.invoke.andReturn(
 | 
			
		||||
                    Promise.resolve([child])
 | 
			
		||||
                );
 | 
			
		||||
                context.domainObject = parent;
 | 
			
		||||
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    action.perform();
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "Exported tree sohuld have been built");
 | 
			
		||||
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect(Object.keys(action.tree).length).toBe(1);
 | 
			
		||||
                    expect(action.tree.hasOwnProperty("parentId"))
 | 
			
		||||
                        .toBeTruthy();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("can export self-containing objects", function () {
 | 
			
		||||
                var infiniteParentComposition =
 | 
			
		||||
                    jasmine.createSpyObj('infiniteParentComposition',
 | 
			
		||||
                        ['invoke']
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                var infiniteChildComposition =
 | 
			
		||||
                    jasmine.createSpyObj('infiniteChildComposition',
 | 
			
		||||
                        ['invoke']
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                var parent = domainObjectFactory({
 | 
			
		||||
                    name: 'parent',
 | 
			
		||||
                    model: { name: 'parent', location: 'ROOT'},
 | 
			
		||||
                    id: 'infiniteParentId',
 | 
			
		||||
                    capabilities: {
 | 
			
		||||
                        composition: infiniteParentComposition,
 | 
			
		||||
                        type: mockType
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                var child = domainObjectFactory({
 | 
			
		||||
                    name: 'child',
 | 
			
		||||
                    model: { name: 'child', location: 'infiniteParentId' },
 | 
			
		||||
                    id: 'infiniteChildId',
 | 
			
		||||
                    capabilities: {
 | 
			
		||||
                        composition: infiniteChildComposition,
 | 
			
		||||
                        type: mockType
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                infiniteParentComposition.invoke.andReturn(
 | 
			
		||||
                    Promise.resolve([child])
 | 
			
		||||
                );
 | 
			
		||||
                infiniteChildComposition.invoke.andReturn(
 | 
			
		||||
                    Promise.resolve([parent])
 | 
			
		||||
                );
 | 
			
		||||
                context.domainObject = parent;
 | 
			
		||||
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    action.perform();
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "Exported tree sohuld have been built");
 | 
			
		||||
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect(Object.keys(action.tree).length).toBe(2);
 | 
			
		||||
                    expect(action.tree.hasOwnProperty("infiniteParentId"))
 | 
			
		||||
                        .toBeTruthy();
 | 
			
		||||
                    expect(action.tree.hasOwnProperty("infiniteChildId"))
 | 
			
		||||
                        .toBeTruthy();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("exports links to external objects as new objects", function () {
 | 
			
		||||
                var externallyLinkedComposition =
 | 
			
		||||
                    jasmine.createSpyObj('externallyLinkedComposition',
 | 
			
		||||
                        ['invoke']
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                var parent = domainObjectFactory({
 | 
			
		||||
                    name: 'parent',
 | 
			
		||||
                    model: {
 | 
			
		||||
                        name: 'parent',
 | 
			
		||||
                        composition: ['externalId'],
 | 
			
		||||
                        location: 'ROOT'},
 | 
			
		||||
                    id: 'parentId',
 | 
			
		||||
                    capabilities: {
 | 
			
		||||
                        composition: externallyLinkedComposition,
 | 
			
		||||
                        type: mockType
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                var externalObject = domainObjectFactory({
 | 
			
		||||
                    name: 'external',
 | 
			
		||||
                    model: { name: 'external', location: 'outsideOfTree'},
 | 
			
		||||
                    id: 'externalId',
 | 
			
		||||
                    capabilities: {
 | 
			
		||||
                        type: mockType
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                externallyLinkedComposition.invoke.andReturn(
 | 
			
		||||
                    Promise.resolve([externalObject])
 | 
			
		||||
                );
 | 
			
		||||
                context.domainObject = parent;
 | 
			
		||||
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    action.perform();
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "Exported tree sohuld have been built");
 | 
			
		||||
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect(Object.keys(action.tree).length).toBe(2);
 | 
			
		||||
                    expect(action.tree.hasOwnProperty('parentId'))
 | 
			
		||||
                        .toBeTruthy();
 | 
			
		||||
                    expect(action.tree.hasOwnProperty('brandNewId'))
 | 
			
		||||
                        .toBeTruthy();
 | 
			
		||||
                    expect(action.tree.brandNewId.location).toBe('parentId');
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("exports object tree in the correct format", function () {
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    action.perform();
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "Exported tree sohuld have been built");
 | 
			
		||||
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect(Object.keys(exportedTree).length).toBe(2);
 | 
			
		||||
                    expect(exportedTree.hasOwnProperty('openmct')).toBeTruthy();
 | 
			
		||||
                    expect(exportedTree.hasOwnProperty('rootId')).toBeTruthy();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,240 +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(
 | 
			
		||||
    [
 | 
			
		||||
        "../../src/actions/ImportAsJSONAction",
 | 
			
		||||
        "../../../entanglement/test/DomainObjectFactory"
 | 
			
		||||
    ],
 | 
			
		||||
    function (ImportAsJSONAction, domainObjectFactory) {
 | 
			
		||||
 | 
			
		||||
        describe("The import JSON action", function () {
 | 
			
		||||
 | 
			
		||||
            var context = {};
 | 
			
		||||
            var action,
 | 
			
		||||
                exportService,
 | 
			
		||||
                identifierService,
 | 
			
		||||
                dialogService,
 | 
			
		||||
                openmct,
 | 
			
		||||
                mockDialog,
 | 
			
		||||
                compositionCapability,
 | 
			
		||||
                mockInstantiate,
 | 
			
		||||
                uniqueId,
 | 
			
		||||
                newObjects;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
 | 
			
		||||
                uniqueId = 0;
 | 
			
		||||
                newObjects = [];
 | 
			
		||||
                openmct = {
 | 
			
		||||
                    $injector: jasmine.createSpyObj('$injector', ['get'])
 | 
			
		||||
                };
 | 
			
		||||
                mockInstantiate = jasmine.createSpy('instantiate').andCallFake(
 | 
			
		||||
                    function (model, id) {
 | 
			
		||||
                        var config = {
 | 
			
		||||
                            "model": model,
 | 
			
		||||
                            "id": id,
 | 
			
		||||
                            "capabilities": {}
 | 
			
		||||
                        };
 | 
			
		||||
                        var locationCapability = {
 | 
			
		||||
                            setPrimaryLocation: jasmine.createSpy
 | 
			
		||||
                                ('setPrimaryLocation').andCallFake(
 | 
			
		||||
                                    function (newLocation) {
 | 
			
		||||
                                        config.model.location = newLocation;
 | 
			
		||||
                                    }
 | 
			
		||||
                                )
 | 
			
		||||
                        };
 | 
			
		||||
                        config.capabilities.location = locationCapability;
 | 
			
		||||
                        if (model.composition) {
 | 
			
		||||
                            var compCapability =
 | 
			
		||||
                                jasmine.createSpy('compCapability')
 | 
			
		||||
                                .andReturn(model.composition);
 | 
			
		||||
                            compCapability.add = jasmine.createSpy('add')
 | 
			
		||||
                                .andCallFake(function (newObj) {
 | 
			
		||||
                                    config.model.composition.push(newObj.getId());
 | 
			
		||||
                                });
 | 
			
		||||
                            config.capabilities.composition = compCapability;
 | 
			
		||||
                        }
 | 
			
		||||
                        newObjects.push(domainObjectFactory(config));
 | 
			
		||||
                        return domainObjectFactory(config);
 | 
			
		||||
                    });
 | 
			
		||||
                openmct.$injector.get.andReturn(mockInstantiate);
 | 
			
		||||
                dialogService = jasmine.createSpyObj('dialogService',
 | 
			
		||||
                    [
 | 
			
		||||
                        'getUserInput',
 | 
			
		||||
                        'showBlockingMessage'
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                identifierService = jasmine.createSpyObj('identifierService',
 | 
			
		||||
                    [
 | 
			
		||||
                        'generate'
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                identifierService.generate.andCallFake(function () {
 | 
			
		||||
                    uniqueId++;
 | 
			
		||||
                    return uniqueId;
 | 
			
		||||
                });
 | 
			
		||||
                compositionCapability = jasmine.createSpy('compositionCapability');
 | 
			
		||||
                mockDialog = jasmine.createSpyObj("dialog", ["dismiss"]);
 | 
			
		||||
                dialogService.showBlockingMessage.andReturn(mockDialog);
 | 
			
		||||
 | 
			
		||||
                action = new ImportAsJSONAction(exportService, identifierService,
 | 
			
		||||
                    dialogService, openmct, context);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("initializes happily", function () {
 | 
			
		||||
                expect(action).toBeDefined();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("only applies to objects with composition capability", function () {
 | 
			
		||||
                var compDomainObject = domainObjectFactory({
 | 
			
		||||
                    name: 'compObject',
 | 
			
		||||
                    model: { name: 'compObject'},
 | 
			
		||||
                    capabilities: {"composition": compositionCapability}
 | 
			
		||||
                });
 | 
			
		||||
                var noCompDomainObject = domainObjectFactory();
 | 
			
		||||
 | 
			
		||||
                context.domainObject = compDomainObject;
 | 
			
		||||
                expect(ImportAsJSONAction.appliesTo(context)).toBe(true);
 | 
			
		||||
                context.domainObject = noCompDomainObject;
 | 
			
		||||
                expect(ImportAsJSONAction.appliesTo(context)).toBe(false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("displays error dialog on invalid file choice", function () {
 | 
			
		||||
                dialogService.getUserInput.andReturn(Promise.resolve(
 | 
			
		||||
                    {
 | 
			
		||||
                        selectFile: {
 | 
			
		||||
                            body: JSON.stringify({badKey: "INVALID"}),
 | 
			
		||||
                            name: "fileName"
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    action.perform();
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "Promise containing file data should have resolved");
 | 
			
		||||
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect(dialogService.getUserInput).toHaveBeenCalled();
 | 
			
		||||
                    expect(dialogService.showBlockingMessage).toHaveBeenCalled();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("can import self-containing objects", function () {
 | 
			
		||||
                dialogService.getUserInput.andReturn(Promise.resolve(
 | 
			
		||||
                    {
 | 
			
		||||
                        selectFile: {
 | 
			
		||||
                            body: JSON.stringify({
 | 
			
		||||
                                "openmct": {
 | 
			
		||||
                                    "infiniteParent": {
 | 
			
		||||
                                        "composition": ["infinteChild"],
 | 
			
		||||
                                        "name": "1",
 | 
			
		||||
                                        "type": "folder",
 | 
			
		||||
                                        "modified": 1503598129176,
 | 
			
		||||
                                        "location": "mine",
 | 
			
		||||
                                        "persisted": 1503598129176
 | 
			
		||||
                                    },
 | 
			
		||||
                                    "infinteChild": {
 | 
			
		||||
                                        "composition": ["infiniteParent"],
 | 
			
		||||
                                        "name": "2",
 | 
			
		||||
                                        "type": "folder",
 | 
			
		||||
                                        "modified": 1503598132428,
 | 
			
		||||
                                        "location": "infiniteParent",
 | 
			
		||||
                                        "persisted": 1503598132428
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                "rootId": "infiniteParent"
 | 
			
		||||
                            }),
 | 
			
		||||
                            name: "fileName"
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    action.perform();
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "Promise containing file data should have resolved");
 | 
			
		||||
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect(mockInstantiate.calls.length).toEqual(2);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("assigns new ids to each imported object", function () {
 | 
			
		||||
                dialogService.getUserInput.andReturn(Promise.resolve(
 | 
			
		||||
                    {
 | 
			
		||||
                        selectFile: {
 | 
			
		||||
                            body: JSON.stringify({
 | 
			
		||||
                                "openmct": {
 | 
			
		||||
                                    "cce9f107-5060-4f55-8151-a00120f4222f": {
 | 
			
		||||
                                        "composition": [],
 | 
			
		||||
                                        "name": "test",
 | 
			
		||||
                                        "type": "folder",
 | 
			
		||||
                                        "modified": 1503596596639,
 | 
			
		||||
                                        "location": "mine",
 | 
			
		||||
                                        "persisted": 1503596596639
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                "rootId": "cce9f107-5060-4f55-8151-a00120f4222f"
 | 
			
		||||
                            }),
 | 
			
		||||
                            name: "fileName"
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                var init = false;
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    action.perform();
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        init = true;
 | 
			
		||||
                    }, 100);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                waitsFor(function () {
 | 
			
		||||
                    return init;
 | 
			
		||||
                }, "Promise containing file data should have resolved");
 | 
			
		||||
 | 
			
		||||
                runs(function () {
 | 
			
		||||
                    expect(mockInstantiate.calls.length).toEqual(1);
 | 
			
		||||
                    expect(newObjects[0].getId()).toBe('1');
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -25,12 +25,10 @@
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        '../../../src/api/objects/object-utils',
 | 
			
		||||
        'lodash'
 | 
			
		||||
        '../../../src/api/objects/object-utils'
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        objectUtils,
 | 
			
		||||
        _
 | 
			
		||||
        objectUtils
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        var ZERO = function () {
 | 
			
		||||
@@ -140,11 +138,6 @@ define(
 | 
			
		||||
                typeRequest = (type && type.getDefinition().telemetry) || {},
 | 
			
		||||
                modelTelemetry = domainObject.getModel().telemetry,
 | 
			
		||||
                fullRequest = Object.create(typeRequest),
 | 
			
		||||
                newObject = objectUtils.toNewFormat(
 | 
			
		||||
                    domainObject.getModel(),
 | 
			
		||||
                    domainObject.getId()
 | 
			
		||||
                ),
 | 
			
		||||
                metadata = this.openmct.telemetry.getMetadata(newObject),
 | 
			
		||||
                bounds,
 | 
			
		||||
                timeSystem;
 | 
			
		||||
 | 
			
		||||
@@ -180,28 +173,17 @@ define(
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!fullRequest.ranges) {
 | 
			
		||||
                fullRequest.ranges = metadata.valuesForHints(['range']);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!fullRequest.domains) {
 | 
			
		||||
                fullRequest.domains = metadata.valuesForHints(['domain']);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return fullRequest;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        function asSeries(telemetry, defaultDomain, defaultRange, sourceMap) {
 | 
			
		||||
            function getValue(index, key) {
 | 
			
		||||
                return telemetry[index][sourceMap[key].source];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        function asSeries(telemetry, defaultDomain, defaultRange) {
 | 
			
		||||
            return {
 | 
			
		||||
                getRangeValue: function (index, range) {
 | 
			
		||||
                    return getValue(index, range || defaultRange);
 | 
			
		||||
                    return telemetry[index][range || defaultRange];
 | 
			
		||||
                },
 | 
			
		||||
                getDomainValue: function (index, domain) {
 | 
			
		||||
                    return getValue(index, domain || defaultDomain);
 | 
			
		||||
                    return telemetry[index][domain || defaultDomain];
 | 
			
		||||
                },
 | 
			
		||||
                getPointCount: function () {
 | 
			
		||||
                    return telemetry.length;
 | 
			
		||||
@@ -228,11 +210,9 @@ define(
 | 
			
		||||
            var telemetryAPI = this.openmct.telemetry;
 | 
			
		||||
 | 
			
		||||
            var metadata = telemetryAPI.getMetadata(domainObject);
 | 
			
		||||
            var defaultDomain = metadata.valuesForHints(['domain'])[0].key;
 | 
			
		||||
            var defaultDomain = metadata.valuesForHints(['domain'])[0].source;
 | 
			
		||||
            var defaultRange = metadata.valuesForHints(['range'])[0];
 | 
			
		||||
            defaultRange = defaultRange ? defaultRange.key : undefined;
 | 
			
		||||
 | 
			
		||||
            var sourceMap = _.indexBy(metadata.values(), 'key');
 | 
			
		||||
            defaultRange = defaultRange ? defaultRange.source : undefined;
 | 
			
		||||
 | 
			
		||||
            var isLegacyProvider = telemetryAPI.findRequestProvider(domainObject) ===
 | 
			
		||||
                telemetryAPI.legacyProvider;
 | 
			
		||||
@@ -257,7 +237,7 @@ define(
 | 
			
		||||
                    requestTelemetryFromService().then(getRelevantResponse);
 | 
			
		||||
            } else {
 | 
			
		||||
                return telemetryAPI.request(domainObject, fullRequest).then(function (telemetry) {
 | 
			
		||||
                    return asSeries(telemetry, defaultDomain, defaultRange, sourceMap);
 | 
			
		||||
                    return asSeries(telemetry, defaultDomain, defaultRange);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
@@ -293,17 +273,15 @@ define(
 | 
			
		||||
            var telemetryAPI = this.openmct.telemetry;
 | 
			
		||||
 | 
			
		||||
            var metadata = telemetryAPI.getMetadata(domainObject);
 | 
			
		||||
            var defaultDomain = metadata.valuesForHints(['domain'])[0].key;
 | 
			
		||||
            var defaultDomain = metadata.valuesForHints(['domain'])[0].source;
 | 
			
		||||
            var defaultRange = metadata.valuesForHints(['range'])[0];
 | 
			
		||||
            defaultRange = defaultRange ? defaultRange.key : undefined;
 | 
			
		||||
 | 
			
		||||
            var sourceMap = _.indexBy(metadata.values(), 'key');
 | 
			
		||||
            defaultRange = defaultRange ? defaultRange.source : undefined;
 | 
			
		||||
 | 
			
		||||
            var isLegacyProvider = telemetryAPI.findSubscriptionProvider(domainObject) ===
 | 
			
		||||
                telemetryAPI.legacyProvider;
 | 
			
		||||
 | 
			
		||||
            function update(telemetry) {
 | 
			
		||||
                callback(asSeries([telemetry], defaultDomain, defaultRange, sourceMap));
 | 
			
		||||
                callback(asSeries([telemetry], defaultDomain, defaultRange));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Unpack the relevant telemetry series
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,6 @@ define(
 | 
			
		||||
                mockUnsubscribe,
 | 
			
		||||
                telemetry,
 | 
			
		||||
                mockTelemetryAPI,
 | 
			
		||||
                mockMetadata,
 | 
			
		||||
                mockAPI;
 | 
			
		||||
 | 
			
		||||
            function mockPromise(value) {
 | 
			
		||||
@@ -91,23 +90,12 @@ define(
 | 
			
		||||
                    "findRequestProvider",
 | 
			
		||||
                    "findSubscriptionProvider"
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                mockMetadata = jasmine.createSpyObj('telemetryMetadata', [
 | 
			
		||||
                    'valuesForHints',
 | 
			
		||||
                    'values'
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                mockMetadata.valuesForHints.andCallFake(function (hints) {
 | 
			
		||||
                    var hint = hints[0];
 | 
			
		||||
                    var metadatum = {
 | 
			
		||||
                        key: 'default' + hint
 | 
			
		||||
                    };
 | 
			
		||||
                    metadatum[hint] = "foo";
 | 
			
		||||
                    return [metadatum];
 | 
			
		||||
                mockTelemetryAPI.getMetadata.andReturn({
 | 
			
		||||
                    valuesForHints: function () {
 | 
			
		||||
                        return [{}];
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mockTelemetryAPI.getMetadata.andReturn(mockMetadata);
 | 
			
		||||
 | 
			
		||||
                mockAPI = {
 | 
			
		||||
                    telemetry: mockTelemetryAPI,
 | 
			
		||||
                    time: {
 | 
			
		||||
@@ -159,9 +147,7 @@ define(
 | 
			
		||||
                        source: "testSource", // from model
 | 
			
		||||
                        key: "testKey", // from model
 | 
			
		||||
                        start: 42, // from argument
 | 
			
		||||
                        domain: 'mockTimeSystem',
 | 
			
		||||
                        domains: [{ domain: "foo", key: 'defaultdomain' }],
 | 
			
		||||
                        ranges: [{ range: "foo", key: 'defaultrange' }]
 | 
			
		||||
                        domain: 'mockTimeSystem'
 | 
			
		||||
                    }]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -181,9 +167,7 @@ define(
 | 
			
		||||
                    key: "testKey",
 | 
			
		||||
                    start: 0,
 | 
			
		||||
                    end: 1,
 | 
			
		||||
                    domain: 'mockTimeSystem',
 | 
			
		||||
                    domains: [{ domain: "foo", key: 'defaultdomain' }],
 | 
			
		||||
                    ranges: [{ range: "foo", key: 'defaultrange' }]
 | 
			
		||||
                    domain: 'mockTimeSystem'
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -200,9 +184,7 @@ define(
 | 
			
		||||
                    key: "testId", // from domain object
 | 
			
		||||
                    start: 0,
 | 
			
		||||
                    end: 1,
 | 
			
		||||
                    domain: 'mockTimeSystem',
 | 
			
		||||
                    domains: [{ domain: "foo", key: 'defaultdomain' }],
 | 
			
		||||
                    ranges: [{ range: "foo", key: 'defaultrange' }]
 | 
			
		||||
                    domain: 'mockTimeSystem'
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -250,21 +232,6 @@ define(
 | 
			
		||||
                var mockProvider = {};
 | 
			
		||||
                var dunzo = false;
 | 
			
		||||
 | 
			
		||||
                mockMetadata.values.andReturn([
 | 
			
		||||
                    {
 | 
			
		||||
                        key: 'defaultrange',
 | 
			
		||||
                        source: 'prop1'
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        key: 'defaultdomain',
 | 
			
		||||
                        source: 'prop2'
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        key: 'prop3',
 | 
			
		||||
                        source: 'prop3'
 | 
			
		||||
                    }
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                mockTelemetryAPI.findRequestProvider.andReturn(mockProvider);
 | 
			
		||||
                mockTelemetryAPI.request.andReturn(Promise.resolve(mockTelemetry));
 | 
			
		||||
 | 
			
		||||
@@ -282,18 +249,6 @@ define(
 | 
			
		||||
                    expect(returnedTelemetry.getDomainValue).toBeDefined();
 | 
			
		||||
                    expect(returnedTelemetry.getRangeValue).toBeDefined();
 | 
			
		||||
                    expect(returnedTelemetry.getPointCount()).toBe(2);
 | 
			
		||||
                    // Default domain + remap should work.
 | 
			
		||||
                    expect(returnedTelemetry.getDomainValue(0)).toBe('val2');
 | 
			
		||||
                    expect(returnedTelemetry.getDomainValue(1)).toBe('val5');
 | 
			
		||||
                    // explicit domain should work
 | 
			
		||||
                    expect(returnedTelemetry.getDomainValue(0, 'prop3')).toBe('val3');
 | 
			
		||||
                    expect(returnedTelemetry.getDomainValue(1, 'prop3')).toBe('val6');
 | 
			
		||||
                    // default range + remap should work
 | 
			
		||||
                    expect(returnedTelemetry.getRangeValue(0)).toBe('val1');
 | 
			
		||||
                    expect(returnedTelemetry.getRangeValue(1)).toBe('val4');
 | 
			
		||||
                    // explicit range should work
 | 
			
		||||
                    expect(returnedTelemetry.getRangeValue(0, 'prop3')).toBe('val3');
 | 
			
		||||
                    expect(returnedTelemetry.getRangeValue(1, 'prop3')).toBe('val6');
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
@@ -311,9 +266,7 @@ define(
 | 
			
		||||
                        key: "testKey",
 | 
			
		||||
                        start: 0,
 | 
			
		||||
                        end: 1,
 | 
			
		||||
                        domain: 'mockTimeSystem',
 | 
			
		||||
                        domains: [{ domain: "foo", key: "defaultdomain" }],
 | 
			
		||||
                        ranges: [{ range: "foo", key: "defaultrange" }]
 | 
			
		||||
                        domain: 'mockTimeSystem'
 | 
			
		||||
                    }]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								src/MCT.js
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/MCT.js
									
									
									
									
									
								
							@@ -106,9 +106,9 @@ define([
 | 
			
		||||
         *
 | 
			
		||||
         * @type {module:openmct.ViewRegistry}
 | 
			
		||||
         * @memberof module:openmct.MCT#
 | 
			
		||||
         * @name mainViews
 | 
			
		||||
         * @name objectViews
 | 
			
		||||
         */
 | 
			
		||||
        this.mainViews = new ViewRegistry();
 | 
			
		||||
        this.objectViews = new ViewRegistry();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Registry for views which should appear in the Inspector area.
 | 
			
		||||
@@ -255,6 +255,19 @@ define([
 | 
			
		||||
            this.legacyExtension('types', legacyDefinition);
 | 
			
		||||
        }.bind(this));
 | 
			
		||||
 | 
			
		||||
        this.objectViews.providers.forEach(function (p) {
 | 
			
		||||
            this.legacyExtension('views', {
 | 
			
		||||
                key: '_vpid' + p._vpid,
 | 
			
		||||
                vpid: p._vpid,
 | 
			
		||||
                provider: p,
 | 
			
		||||
                name: p.name,
 | 
			
		||||
                cssClass: p.cssClass,
 | 
			
		||||
                description: p.description,
 | 
			
		||||
                editable: p.editable,
 | 
			
		||||
                template: '<mct-view mct-vpid="' + p._vpid + '"/>'
 | 
			
		||||
            });
 | 
			
		||||
        }, this);
 | 
			
		||||
 | 
			
		||||
        legacyRegistry.register('adapter', this.legacyBundle);
 | 
			
		||||
        legacyRegistry.enable('adapter');
 | 
			
		||||
        /**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								src/about.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/about.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Open MCT https://nasa.github.io/openmct/
 | 
			
		||||
 * Version: ${version}
 | 
			
		||||
 * Built: ${timestamp}
 | 
			
		||||
 * Revision: ${revision}
 | 
			
		||||
 * Branch: ${branch}
 | 
			
		||||
 */
 | 
			
		||||
@@ -24,7 +24,6 @@ define([
 | 
			
		||||
    'legacyRegistry',
 | 
			
		||||
    './actions/ActionDialogDecorator',
 | 
			
		||||
    './capabilities/AdapterCapability',
 | 
			
		||||
    './controllers/AdaptedViewController',
 | 
			
		||||
    './directives/MCTView',
 | 
			
		||||
    './services/Instantiate',
 | 
			
		||||
    './services/MissingModelCompatibilityDecorator',
 | 
			
		||||
@@ -33,12 +32,10 @@ define([
 | 
			
		||||
    './policies/AdaptedViewPolicy',
 | 
			
		||||
    './runs/AlternateCompositionInitializer',
 | 
			
		||||
    './runs/TimeSettingsURLHandler',
 | 
			
		||||
    'text!./templates/adapted-view-template.html'
 | 
			
		||||
], function (
 | 
			
		||||
    legacyRegistry,
 | 
			
		||||
    ActionDialogDecorator,
 | 
			
		||||
    AdapterCapability,
 | 
			
		||||
    AdaptedViewController,
 | 
			
		||||
    MCTView,
 | 
			
		||||
    Instantiate,
 | 
			
		||||
    MissingModelCompatibilityDecorator,
 | 
			
		||||
@@ -46,15 +43,15 @@ define([
 | 
			
		||||
    AdapterCompositionPolicy,
 | 
			
		||||
    AdaptedViewPolicy,
 | 
			
		||||
    AlternateCompositionInitializer,
 | 
			
		||||
    TimeSettingsURLHandler,
 | 
			
		||||
    adaptedViewTemplate
 | 
			
		||||
    TimeSettingsURLHandler
 | 
			
		||||
) {
 | 
			
		||||
    legacyRegistry.register('src/adapter', {
 | 
			
		||||
        "extensions": {
 | 
			
		||||
            "directives": [
 | 
			
		||||
                {
 | 
			
		||||
                    key: "mctView",
 | 
			
		||||
                    implementation: MCTView
 | 
			
		||||
                    implementation: MCTView,
 | 
			
		||||
                    depends: ["openmct"]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            capabilities: [
 | 
			
		||||
@@ -63,16 +60,6 @@ define([
 | 
			
		||||
                    implementation: AdapterCapability
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            controllers: [
 | 
			
		||||
                {
 | 
			
		||||
                    key: "AdaptedViewController",
 | 
			
		||||
                    implementation: AdaptedViewController,
 | 
			
		||||
                    depends: [
 | 
			
		||||
                        '$scope',
 | 
			
		||||
                        'openmct'
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            services: [
 | 
			
		||||
                {
 | 
			
		||||
                    key: "instantiate",
 | 
			
		||||
@@ -135,12 +122,6 @@ define([
 | 
			
		||||
                    depends: ["openmct", "$location", "$rootScope"]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            views: [
 | 
			
		||||
                {
 | 
			
		||||
                    key: "adapted-view",
 | 
			
		||||
                    template: adaptedViewTemplate
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            licenses: [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "almond",
 | 
			
		||||
 
 | 
			
		||||
@@ -22,10 +22,12 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './synchronizeMutationCapability',
 | 
			
		||||
    './AlternateCompositionCapability'
 | 
			
		||||
    './AlternateCompositionCapability',
 | 
			
		||||
    './patchViewCapability'
 | 
			
		||||
], function (
 | 
			
		||||
    synchronizeMutationCapability,
 | 
			
		||||
    AlternateCompositionCapability
 | 
			
		||||
    AlternateCompositionCapability,
 | 
			
		||||
    patchViewCapability
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -46,6 +48,9 @@ define([
 | 
			
		||||
            capabilities.mutation =
 | 
			
		||||
                synchronizeMutationCapability(capabilities.mutation);
 | 
			
		||||
        }
 | 
			
		||||
        if (capabilities.view) {
 | 
			
		||||
            capabilities.view = patchViewCapability(capabilities.view);
 | 
			
		||||
        }
 | 
			
		||||
        if (AlternateCompositionCapability.appliesTo(model, id)) {
 | 
			
		||||
            capabilities.composition = function (domainObject) {
 | 
			
		||||
                return new AlternateCompositionCapability(this.$injector, domainObject);
 | 
			
		||||
 
 | 
			
		||||
@@ -20,21 +20,42 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([], function () {
 | 
			
		||||
    function AdaptedViewController($scope, openmct) {
 | 
			
		||||
        function refresh(legacyObject) {
 | 
			
		||||
            if (!legacyObject) {
 | 
			
		||||
                $scope.view = undefined;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
define([
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    _
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
            var domainObject = legacyObject.useCapability('adapter');
 | 
			
		||||
            var providers = openmct.mainViews.get(domainObject);
 | 
			
		||||
            $scope.view = providers[0] && providers[0].view(domainObject);
 | 
			
		||||
    function patchViewCapability(viewConstructor) {
 | 
			
		||||
        return function makeCapability(domainObject) {
 | 
			
		||||
            var capability = viewConstructor(domainObject);
 | 
			
		||||
            var oldInvoke = capability.invoke.bind(capability);
 | 
			
		||||
 | 
			
		||||
            capability.invoke = function () {
 | 
			
		||||
                var availableViews = oldInvoke();
 | 
			
		||||
                var newDomainObject = capability
 | 
			
		||||
                    .domainObject
 | 
			
		||||
                    .useCapability('adapter');
 | 
			
		||||
 | 
			
		||||
                return _(availableViews).map(function (v, i) {
 | 
			
		||||
                    var vd = {
 | 
			
		||||
                        view: v,
 | 
			
		||||
                        priority: i + 100 // arbitrary to allow new views to
 | 
			
		||||
                        // be defaults by returning priority less than 100.
 | 
			
		||||
                    };
 | 
			
		||||
                    if (v.provider) {
 | 
			
		||||
                        vd.priority = v.provider.canView(newDomainObject);
 | 
			
		||||
                    }
 | 
			
		||||
                    return vd;
 | 
			
		||||
                })
 | 
			
		||||
                .sortBy('priority')
 | 
			
		||||
                .map('view')
 | 
			
		||||
                .value();
 | 
			
		||||
            }
 | 
			
		||||
            return capability;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $scope.$watch('domainObject', refresh);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return AdaptedViewController;
 | 
			
		||||
    return patchViewCapability;
 | 
			
		||||
});
 | 
			
		||||
@@ -21,18 +21,20 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    'angular',
 | 
			
		||||
    './Region'
 | 
			
		||||
], function (
 | 
			
		||||
    angular,
 | 
			
		||||
    Region
 | 
			
		||||
) {
 | 
			
		||||
    function MCTView() {
 | 
			
		||||
    function MCTView(openmct) {
 | 
			
		||||
        return {
 | 
			
		||||
            restrict: 'A',
 | 
			
		||||
            restrict: 'E',
 | 
			
		||||
            link: function (scope, element, attrs) {
 | 
			
		||||
                var region = new Region(element[0]);
 | 
			
		||||
                scope.$watch(attrs.mctView, region.show.bind(region));
 | 
			
		||||
                var provider = openmct.objectViews._getByVPID(Number(attrs.mctVpid));
 | 
			
		||||
                var view = new provider.view(scope.domainObject.useCapability('adapter'));
 | 
			
		||||
                view.show(element[0]);
 | 
			
		||||
                if (view.destroy) {
 | 
			
		||||
                    scope.$on('$destroy', function () {
 | 
			
		||||
                        view.destroy(element[0])
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,45 +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 Region(element) {
 | 
			
		||||
        this.activeView = undefined;
 | 
			
		||||
        this.element = element;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Region.prototype.clear = function () {
 | 
			
		||||
        if (this.activeView) {
 | 
			
		||||
            this.activeView.destroy();
 | 
			
		||||
            this.activeView = undefined;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Region.prototype.show = function (view) {
 | 
			
		||||
        this.clear();
 | 
			
		||||
        this.activeView = view;
 | 
			
		||||
        if (this.activeView) {
 | 
			
		||||
            this.activeView.show(this.element);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return Region;
 | 
			
		||||
});
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user