Compare commits
	
		
			215 Commits
		
	
	
		
			snapshot-f
			...
			mobile_ges
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8072e829ad | ||
| 
						 | 
					e866ddb9fd | ||
| 
						 | 
					4fa29d30f5 | ||
| 
						 | 
					c394151c46 | ||
| 
						 | 
					db1b76413c | ||
| 
						 | 
					c8b02d355f | ||
| 
						 | 
					7c110ee8af | ||
| 
						 | 
					49213f550f | ||
| 
						 | 
					447ae3f20b | ||
| 
						 | 
					7288db1908 | ||
| 
						 | 
					908fbdbf73 | ||
| 
						 | 
					052a359738 | ||
| 
						 | 
					f9be00a70f | ||
| 
						 | 
					d1055f0839 | ||
| 
						 | 
					0b7ab75512 | ||
| 
						 | 
					9d1841db55 | ||
| 
						 | 
					50d10639e1 | ||
| 
						 | 
					5a9619ce26 | ||
| 
						 | 
					42b7427816 | ||
| 
						 | 
					a1b37b1269 | ||
| 
						 | 
					c8ca1deb9b | ||
| 
						 | 
					5be6e90388 | ||
| 
						 | 
					814b04858a | ||
| 
						 | 
					aedbd3bd9b | ||
| 
						 | 
					aa4dbf7062 | ||
| 
						 | 
					5b95574673 | ||
| 
						 | 
					2295be5e35 | ||
| 
						 | 
					0ac6caa823 | ||
| 
						 | 
					5e1dd04e6d | ||
| 
						 | 
					29df378851 | ||
| 
						 | 
					8511c957a0 | ||
| 
						 | 
					f4efc79539 | ||
| 
						 | 
					3926d6f617 | ||
| 
						 | 
					d65e0f820f | ||
| 
						 | 
					24fe419be4 | ||
| 
						 | 
					3e2c3f913b | ||
| 
						 | 
					a45b09277e | ||
| 
						 | 
					bdf3e4d8a3 | ||
| 
						 | 
					e4a2904213 | ||
| 
						 | 
					f1d4e36c02 | ||
| 
						 | 
					b3792c21be | ||
| 
						 | 
					1fbbf355f4 | ||
| 
						 | 
					9fec73da14 | ||
| 
						 | 
					23048f0df9 | ||
| 
						 | 
					dfe3409a98 | ||
| 
						 | 
					5c3fe78bd5 | ||
| 
						 | 
					eb69e02ce3 | ||
| 
						 | 
					17e2da2d2c | ||
| 
						 | 
					03db1b3623 | ||
| 
						 | 
					5c23daa5ff | ||
| 
						 | 
					056b3f61ce | ||
| 
						 | 
					a0dc3da8fb | ||
| 
						 | 
					48f345a46b | ||
| 
						 | 
					2cf7f6794c | ||
| 
						 | 
					889a5c6ea9 | ||
| 
						 | 
					5502009127 | ||
| 
						 | 
					cb41be7922 | ||
| 
						 | 
					2997f2a261 | ||
| 
						 | 
					52b8720d37 | ||
| 
						 | 
					bb8c8a75ab | ||
| 
						 | 
					d10c56f732 | ||
| 
						 | 
					1f7d0427b7 | ||
| 
						 | 
					caf1e3aea9 | ||
| 
						 | 
					3031579a62 | ||
| 
						 | 
					00aa7ce0c2 | ||
| 
						 | 
					cac97401c6 | ||
| 
						 | 
					7b371327e6 | ||
| 
						 | 
					113d1c909f | ||
| 
						 | 
					7ca15a9de2 | ||
| 
						 | 
					dcd7d61c9a | ||
| 
						 | 
					0a39984c4f | ||
| 
						 | 
					0b635afcf7 | ||
| 
						 | 
					f46a0853b9 | ||
| 
						 | 
					6b65ae77e7 | ||
| 
						 | 
					66408eeec8 | ||
| 
						 | 
					3d524d7572 | ||
| 
						 | 
					9b922913a0 | ||
| 
						 | 
					560a2e035e | ||
| 
						 | 
					eca52a8ca6 | ||
| 
						 | 
					25e8bb44d2 | ||
| 
						 | 
					85658d3d1f | ||
| 
						 | 
					ddce0f371d | ||
| 
						 | 
					495cd06ed5 | ||
| 
						 | 
					1624866656 | ||
| 
						 | 
					2d1aa65d63 | ||
| 
						 | 
					c333a2e70a | ||
| 
						 | 
					906354764b | ||
| 
						 | 
					12ec293f3d | ||
| 
						 | 
					bdf8b4d3f1 | ||
| 
						 | 
					6e60088b11 | ||
| 
						 | 
					97bf530b1d | ||
| 
						 | 
					18348476c6 | ||
| 
						 | 
					7e35e55f0b | ||
| 
						 | 
					28a2a5b92a | ||
| 
						 | 
					d262520594 | ||
| 
						 | 
					7cc14a195b | ||
| 
						 | 
					84b9e4d781 | ||
| 
						 | 
					356fa73c91 | ||
| 
						 | 
					a073ef69ac | ||
| 
						 | 
					3c6c420023 | ||
| 
						 | 
					2a4943f584 | ||
| 
						 | 
					e32403a75f | ||
| 
						 | 
					b0c42c12b7 | ||
| 
						 | 
					621ccc25ec | ||
| 
						 | 
					617df739ee | ||
| 
						 | 
					6e43a92191 | ||
| 
						 | 
					a9418fd2c7 | ||
| 
						 | 
					1d7a0fa48d | ||
| 
						 | 
					30c530178a | ||
| 
						 | 
					3d0795cde3 | ||
| 
						 | 
					c85a3787c0 | ||
| 
						 | 
					066258ab83 | ||
| 
						 | 
					ddc2295ec3 | ||
| 
						 | 
					011e6fc512 | ||
| 
						 | 
					91bd58215a | ||
| 
						 | 
					b37ee19fbc | ||
| 
						 | 
					2355d354b3 | ||
| 
						 | 
					200c6e49fc | ||
| 
						 | 
					a89f9eed42 | ||
| 
						 | 
					7993e4c03f | ||
| 
						 | 
					b592b89dc8 | ||
| 
						 | 
					d115166dde | ||
| 
						 | 
					d176f9f811 | ||
| 
						 | 
					143e3eeb6c | ||
| 
						 | 
					50ce800c2a | ||
| 
						 | 
					1a1eecb4c3 | ||
| 
						 | 
					b3bc8b6876 | ||
| 
						 | 
					1f7ba70ad7 | ||
| 
						 | 
					7aba3b6672 | ||
| 
						 | 
					926b3d075c | ||
| 
						 | 
					827cb27f28 | ||
| 
						 | 
					0842f464db | ||
| 
						 | 
					56e51ea32a | ||
| 
						 | 
					dcdafbaebf | ||
| 
						 | 
					f98915cddd | ||
| 
						 | 
					4e6c307684 | ||
| 
						 | 
					ce6d74390e | ||
| 
						 | 
					6e406fd060 | ||
| 
						 | 
					2614427e0e | ||
| 
						 | 
					272c6bca97 | ||
| 
						 | 
					0d7387080d | ||
| 
						 | 
					1e2e20b145 | ||
| 
						 | 
					488829a20c | ||
| 
						 | 
					85c7a36e25 | ||
| 
						 | 
					d99b4d75d8 | ||
| 
						 | 
					15a88967d0 | ||
| 
						 | 
					6e6fbe0d65 | ||
| 
						 | 
					180e5f14ae | ||
| 
						 | 
					e9314898d2 | ||
| 
						 | 
					ce75d19480 | ||
| 
						 | 
					a9dd1f9828 | ||
| 
						 | 
					4b5540830b | ||
| 
						 | 
					ee35976c92 | ||
| 
						 | 
					54b6cd1100 | ||
| 
						 | 
					0f89e98a71 | ||
| 
						 | 
					6f07a21bb8 | ||
| 
						 | 
					f3678d9d52 | ||
| 
						 | 
					9a7bbd92bd | ||
| 
						 | 
					edcafc5835 | ||
| 
						 | 
					7d09df9a85 | ||
| 
						 | 
					b00eee00fc | ||
| 
						 | 
					c0d83f9395 | ||
| 
						 | 
					be757066f5 | ||
| 
						 | 
					885433390e | ||
| 
						 | 
					687f810475 | ||
| 
						 | 
					137a60f510 | ||
| 
						 | 
					46d5a1431f | ||
| 
						 | 
					404d02ec23 | ||
| 
						 | 
					eec955317a | ||
| 
						 | 
					67890a7298 | ||
| 
						 | 
					dd457f26c6 | ||
| 
						 | 
					85c6bda5c9 | ||
| 
						 | 
					b7b5f87002 | ||
| 
						 | 
					b0c5d807e7 | ||
| 
						 | 
					4d4776e0ef | ||
| 
						 | 
					61e1aeb1d8 | ||
| 
						 | 
					9caa603a65 | ||
| 
						 | 
					5c99e469d5 | ||
| 
						 | 
					4d9dc3624b | ||
| 
						 | 
					d3ae4b729f | ||
| 
						 | 
					30bed434fe | ||
| 
						 | 
					3e4ae4d38d | ||
| 
						 | 
					7414275a85 | ||
| 
						 | 
					fcb0033864 | ||
| 
						 | 
					f079471a18 | ||
| 
						 | 
					1fb1174c0a | ||
| 
						 | 
					635e1eda69 | ||
| 
						 | 
					40d53f941f | ||
| 
						 | 
					684a0e88a2 | ||
| 
						 | 
					30a4f15330 | ||
| 
						 | 
					dfd08000f1 | ||
| 
						 | 
					82c8d26264 | ||
| 
						 | 
					bd236e1cb1 | ||
| 
						 | 
					e47a36e799 | ||
| 
						 | 
					30efec0090 | ||
| 
						 | 
					b9371ea03d | ||
| 
						 | 
					7974f33781 | ||
| 
						 | 
					cdcaedc8dd | ||
| 
						 | 
					07ef4dfe8a | ||
| 
						 | 
					342be0822f | ||
| 
						 | 
					5c56484889 | ||
| 
						 | 
					2b4162c0be | ||
| 
						 | 
					3704d64560 | ||
| 
						 | 
					24fae72492 | ||
| 
						 | 
					79fb6eabd9 | ||
| 
						 | 
					1ddb00c8d6 | ||
| 
						 | 
					8a0b77ec5c | ||
| 
						 | 
					2fc447e16f | ||
| 
						 | 
					d828bf59f9 | ||
| 
						 | 
					d8806f14aa | ||
| 
						 | 
					0c6a9ca857 | ||
| 
						 | 
					07c907b315 | ||
| 
						 | 
					d343d38037 | ||
| 
						 | 
					73241efdc8 | ||
| 
						 | 
					b40494ac95 | 
@@ -14,7 +14,7 @@
 | 
			
		||||
    "platform/features/imagery",
 | 
			
		||||
    "platform/features/layout",
 | 
			
		||||
    "platform/features/pages",
 | 
			
		||||
    "platform/features/plot",
 | 
			
		||||
    "platform/features/plot-reborn",
 | 
			
		||||
    "platform/features/scrolling",
 | 
			
		||||
    "platform/features/events",
 | 
			
		||||
    "platform/forms",
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
<html>
 | 
			
		||||
<head lang="en">
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
 | 
			
		||||
    <title></title>
 | 
			
		||||
    <script type="text/javascript"
 | 
			
		||||
            src="platform/framework/lib/require.js"
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,11 @@
 | 
			
		||||
                "templateUrl": "templates/menu-arrow.html",
 | 
			
		||||
                "uses": [ "action" ],
 | 
			
		||||
                "gestures": [ "menu" ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "back-arrow",
 | 
			
		||||
                "uses": [ "type", "action" ],
 | 
			
		||||
                "templateUrl": "templates/back-arrow.html"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "services": [
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								platform/commonUI/browse/res/templates/back-arrow.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								platform/commonUI/browse/res/templates/back-arrow.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<!-- Back Arrow Icon used on mobile-->
 | 
			
		||||
<span ng-controller="BrowseController"
 | 
			
		||||
      ng-click='backArrow()'
 | 
			
		||||
      ng-class="checkRoot(); atRoot ? 'mobile-back-hide' : 'mobile-back-unhide'">
 | 
			
		||||
    <a class='type-icon icon ui-symbol'>{</a>
 | 
			
		||||
</span>
 | 
			
		||||
@@ -25,8 +25,8 @@
 | 
			
		||||
            <mct-representation key="'object-header'" mct-object="domainObject">
 | 
			
		||||
            </mct-representation>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="btn-bar right abs">
 | 
			
		||||
        <!-- Temporarily, on mobile, the button bar is hidden-->
 | 
			
		||||
        <div class="btn-bar right abs mobile-hide">
 | 
			
		||||
            <mct-representation key="'action-group'"
 | 
			
		||||
                                mct-object="domainObject"
 | 
			
		||||
                                parameters="{ category: 'view-control' }">
 | 
			
		||||
 
 | 
			
		||||
@@ -19,29 +19,31 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div content="jquery-wrapper" class="abs holder-all browse-mode">
 | 
			
		||||
 | 
			
		||||
<div content="jquery-wrapper" class="abs holder-all browse-mode" ng-controller="BrowseController">
 | 
			
		||||
    <mct-include key="'topbar-browse'"></mct-include>
 | 
			
		||||
    <div class="holder browse-area s-browse-area abs" ng-controller="BrowseController">
 | 
			
		||||
    <div class="holder browse-area s-browse-area abs browse-wrapper" ng-class="treeClass ? 'browse-showtree' : 'browse-hidetree'">
 | 
			
		||||
        <mct-split-pane class='contents abs' anchor='left'>
 | 
			
		||||
            <div
 | 
			
		||||
                class='split-pane-component treeview pane left'
 | 
			
		||||
                >
 | 
			
		||||
                <mct-representation key="'create-button'" mct-object="navigatedObject">
 | 
			
		||||
                </mct-representation>
 | 
			
		||||
                <div class='holder tree-holder abs'>
 | 
			
		||||
            <div class='split-pane-component treeview pane mobile-pane left-menu desktop-browse'>
 | 
			
		||||
                <div class='holder tree-holder abs mobile-tree-holder'>
 | 
			
		||||
                    <mct-representation key="'tree'"
 | 
			
		||||
                                        mct-object="domainObject"
 | 
			
		||||
                                        ng-model="treeModel">
 | 
			
		||||
                    </mct-representation>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <mct-splitter></mct-splitter>
 | 
			
		||||
            <div class='split-pane-component items pane'>
 | 
			
		||||
                <div class='holder abs' id='content-area'>
 | 
			
		||||
                    <mct-representation mct-object="navigatedObject" key="'browse-object'">
 | 
			
		||||
                    <mct-representation key="'create-button'" mct-object="navigatedObject">
 | 
			
		||||
                    </mct-representation>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <mct-splitter class="mobile-hide"></mct-splitter>
 | 
			
		||||
                    <div class='split-pane-component items pane mobile-pane right-repr'>
 | 
			
		||||
                        <div class='holder abs' id='content-area'>
 | 
			
		||||
                            <mct-representation mct-object="navigatedObject" key="'browse-object'">
 | 
			
		||||
                            </mct-representation>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    <div class="left s-very-subtle key-properties ui-symbol mobile-menu-icon button-pos" 
 | 
			
		||||
                        ng-click="treeSlide()">m</div>                        
 | 
			
		||||
                    </div>   
 | 
			
		||||
        </mct-split-pane>
 | 
			
		||||
    </div>
 | 
			
		||||
    <mct-include key="'bottombar'"></mct-include>
 | 
			
		||||
 
 | 
			
		||||
@@ -19,11 +19,12 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div class='object-header'>
 | 
			
		||||
<div class='object-header object-header-mobile'>
 | 
			
		||||
    <span class="label s-label">
 | 
			
		||||
        <mct-representation key="'back-arrow'"></mct-representation>
 | 
			
		||||
        <span class='type-icon icon ui-symbol'>{{type.getGlyph()}}</span>
 | 
			
		||||
        <span ng-if="parameters.mode" class='action'>{{parameters.mode}}</span>
 | 
			
		||||
        <span class='type-name'>{{type.getName()}}</span>
 | 
			
		||||
        <span class='type-name mobile-important-hide'>{{type.getName()}}</span>
 | 
			
		||||
        <span class='title-label'>{{model.name}}</span>
 | 
			
		||||
        <mct-representation key="'menu-arrow'" mct-object='domainObject'></mct-representation>
 | 
			
		||||
    </span>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<div class='object-holder abs vscroll'>
 | 
			
		||||
    <mct-representation key="representation.selected.key"
 | 
			
		||||
                        mct-object="representation.selected.key && domainObject">
 | 
			
		||||
    </mct-representation>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -20,13 +20,13 @@
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<!-- For selected, add class 'selected' to outer div -->
 | 
			
		||||
<div class='item grid-item' ng-click='action.perform("navigate")'>
 | 
			
		||||
    <div class="contents abs">
 | 
			
		||||
<div class='item grid-item'>
 | 
			
		||||
    <div class="contents abs mobile-grid-nav" ng-click='action.perform("navigate")'>
 | 
			
		||||
        <div class='top-bar bar abs'>
 | 
			
		||||
            <div class='left abs'>
 | 
			
		||||
                <mct-include key="_checkbox"></mct-include>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class='right abs'>
 | 
			
		||||
            <div class='right abs mobile-right'>
 | 
			
		||||
                <div class='ui-symbol icon alert hidden' onclick="alert('Not yet functional. When this is visible, it means that this object needs to be updated. Clicking will allow that action via a dialog.');">!</div>
 | 
			
		||||
                <div class='ui-symbol icon profile' title="Shared">P</div>
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -44,4 +44,7 @@
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
    <div class="contents abs mobile-info desktop-hide">
 | 
			
		||||
        <mct-representation class="contents abs btn s-very-subtle desktop-hide" key="'info-button'" mct-object="domainObject"></mct-representation>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,6 @@ define(
 | 
			
		||||
                // path to new, addressed, path based on
 | 
			
		||||
                // domainObject
 | 
			
		||||
                $location.path(urlService.urlForLocation("browse", domainObject));
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Callback for updating the in-scope reference to the object
 | 
			
		||||
@@ -126,6 +125,36 @@ define(
 | 
			
		||||
                    navigateTo(domainObject);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Uses the current navigation to get the 
 | 
			
		||||
            // current ContextCapability, then the
 | 
			
		||||
            // parent is gotten from that. If the parent
 | 
			
		||||
            // is not the root, then user is navigated to
 | 
			
		||||
            // parent
 | 
			
		||||
            function navigateToParent() {
 | 
			
		||||
                var parent = navigationService.getNavigation().getCapability('context').getParent(),
 | 
			
		||||
                    grandparent;
 | 
			
		||||
                if (parent.getId() !== ROOT_ID) {
 | 
			
		||||
                    grandparent = parent.getCapability('context').getParent().getId();
 | 
			
		||||
                    navigateTo(parent);
 | 
			
		||||
                    if (grandparent && grandparent !== ROOT_ID) {
 | 
			
		||||
                        $scope.atRoot = false;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $scope.atRoot = true;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    $scope.atRoot = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            function checkRoot() {
 | 
			
		||||
                var parent = navigationService.getNavigation().getCapability('context').getParent();
 | 
			
		||||
                if (parent.getId() !== ROOT_ID) {
 | 
			
		||||
                    $scope.atRoot = false;
 | 
			
		||||
                } else {
 | 
			
		||||
                    $scope.atRoot = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Load the root object, put it in the scope.
 | 
			
		||||
            // Also, load its immediate children, and (possibly)
 | 
			
		||||
@@ -140,7 +169,13 @@ define(
 | 
			
		||||
            $scope.treeModel = {
 | 
			
		||||
                selectedObject: navigationService.getNavigation()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            // SlideMenu boolean used to hide and show
 | 
			
		||||
            // tree menu
 | 
			
		||||
            $scope.treeSlide = function () {
 | 
			
		||||
                $scope.treeClass = !$scope.treeClass;
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            // Listen for changes in navigation state.
 | 
			
		||||
            navigationService.addListener(setNavigation);
 | 
			
		||||
 | 
			
		||||
@@ -151,6 +186,10 @@ define(
 | 
			
		||||
            $scope.$on("$destroy", function () {
 | 
			
		||||
                navigationService.removeListener(setNavigation);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            $scope.backArrow = navigateToParent;
 | 
			
		||||
            
 | 
			
		||||
            $scope.checkRoot = checkRoot;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,9 @@ define(
 | 
			
		||||
                mockUrlService,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockNextObject,
 | 
			
		||||
                mockParentContext,
 | 
			
		||||
                mockParent,
 | 
			
		||||
                mockGrandparent,
 | 
			
		||||
                controller;
 | 
			
		||||
 | 
			
		||||
            function mockPromise(value) {
 | 
			
		||||
@@ -52,7 +55,7 @@ define(
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockScope = jasmine.createSpyObj(
 | 
			
		||||
                    "$scope",
 | 
			
		||||
                    [ "$on", "$watch" ]
 | 
			
		||||
                    [ "$on", "$watch", "treeSlide", "backArrow" ]
 | 
			
		||||
                );
 | 
			
		||||
                mockRoute = { current: { params: {} } };
 | 
			
		||||
                mockLocation = jasmine.createSpyObj(
 | 
			
		||||
@@ -88,6 +91,17 @@ define(
 | 
			
		||||
                    "nextObject",
 | 
			
		||||
                    [ "getId", "getCapability", "getModel", "useCapability" ]
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                mockParentContext = jasmine.createSpyObj('context', ['getParent']);
 | 
			
		||||
                mockParent  = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    [ "getId", "getCapability", "getModel", "useCapability" ]
 | 
			
		||||
                );
 | 
			
		||||
                mockGrandparent  = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    [ "getId", "getCapability", "getModel", "useCapability" ]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockObjectService.getObjects.andReturn(mockPromise({
 | 
			
		||||
                    ROOT: mockRootObject
 | 
			
		||||
@@ -145,6 +159,13 @@ define(
 | 
			
		||||
                );
 | 
			
		||||
                expect(mockScope.navigatedObject).toEqual(mockDomainObject);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            // Mocks the tree slide call that
 | 
			
		||||
            // lets the html code know if the
 | 
			
		||||
            // tree menu is open.
 | 
			
		||||
            it("calls the treeSlide function", function () {
 | 
			
		||||
                mockScope.treeSlide();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("releases its navigation listener when its scope is destroyed", function () {
 | 
			
		||||
                expect(mockScope.$on).toHaveBeenCalledWith(
 | 
			
		||||
@@ -237,7 +258,104 @@ define(
 | 
			
		||||
                    mockUrlService.urlForLocation(mockMode, mockNextObject)
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            it("checks if the user is current navigated to the root", function () {
 | 
			
		||||
                var mockContext = jasmine.createSpyObj('context', ['getParent']);
 | 
			
		||||
                
 | 
			
		||||
                mockRoute.current.params.ids = "ROOT/mine";
 | 
			
		||||
                mockParent.getId.andReturn("ROOT");
 | 
			
		||||
                
 | 
			
		||||
                mockDomainObject.getCapability.andCallFake(function (c) {
 | 
			
		||||
                    return c === 'context' && mockContext;
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                mockNavigationService.getNavigation.andReturn(mockDomainObject);
 | 
			
		||||
                mockContext.getParent.andReturn(mockParent);
 | 
			
		||||
                mockParent.getCapability.andCallFake(function (c) {
 | 
			
		||||
                    return c === 'context' && mockParentContext;
 | 
			
		||||
                });
 | 
			
		||||
                mockParentContext.getParent.andReturn(mockGrandparent);
 | 
			
		||||
                
 | 
			
		||||
                controller = new BrowseController(
 | 
			
		||||
                    mockScope,
 | 
			
		||||
                    mockRoute,
 | 
			
		||||
                    mockLocation,
 | 
			
		||||
                    mockObjectService,
 | 
			
		||||
                    mockNavigationService
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockScope.checkRoot();
 | 
			
		||||
                
 | 
			
		||||
                mockRoute.current.params.ids = "mine/junk";
 | 
			
		||||
                mockParent.getId.andReturn("mine");
 | 
			
		||||
                
 | 
			
		||||
                controller = new BrowseController(
 | 
			
		||||
                    mockScope,
 | 
			
		||||
                    mockRoute,
 | 
			
		||||
                    mockLocation,
 | 
			
		||||
                    mockObjectService,
 | 
			
		||||
                    mockNavigationService
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockScope.checkRoot();
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            // Mocks the back arrow call that
 | 
			
		||||
            // lets the html code know the back
 | 
			
		||||
            // arrow navigation needs to be done
 | 
			
		||||
            it("calls the backArrow function", function () {
 | 
			
		||||
                var mockContext = jasmine.createSpyObj('context', ['getParent']);
 | 
			
		||||
                
 | 
			
		||||
                mockRoute.current.params.ids = "mine/junk";
 | 
			
		||||
                mockParent.getId.andReturn("mine");
 | 
			
		||||
                
 | 
			
		||||
                mockDomainObject.getCapability.andCallFake(function (c) {
 | 
			
		||||
                    return c === 'context' && mockContext;
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                mockNavigationService.getNavigation.andReturn(mockDomainObject);
 | 
			
		||||
                mockContext.getParent.andReturn(mockParent);
 | 
			
		||||
                mockParent.getCapability.andCallFake(function (c) {
 | 
			
		||||
                    return c === 'context' && mockParentContext;
 | 
			
		||||
                });
 | 
			
		||||
                mockParentContext.getParent.andReturn(mockGrandparent);
 | 
			
		||||
                
 | 
			
		||||
                controller = new BrowseController(
 | 
			
		||||
                    mockScope,
 | 
			
		||||
                    mockRoute,
 | 
			
		||||
                    mockLocation,
 | 
			
		||||
                    mockObjectService,
 | 
			
		||||
                    mockNavigationService
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockScope.backArrow();
 | 
			
		||||
                
 | 
			
		||||
                mockRoute.current.params.ids = "mine/lessjunk/morejunk";
 | 
			
		||||
                mockGrandparent.getId.andReturn("mine");
 | 
			
		||||
                
 | 
			
		||||
                controller = new BrowseController(
 | 
			
		||||
                    mockScope,
 | 
			
		||||
                    mockRoute,
 | 
			
		||||
                    mockLocation,
 | 
			
		||||
                    mockObjectService,
 | 
			
		||||
                    mockNavigationService
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockScope.backArrow();
 | 
			
		||||
                
 | 
			
		||||
                mockRoute.current.params.ids = "ROOT/mine";
 | 
			
		||||
                mockParent.getId.andReturn("ROOT");
 | 
			
		||||
                
 | 
			
		||||
                controller = new BrowseController(
 | 
			
		||||
                    mockScope,
 | 
			
		||||
                    mockRoute,
 | 
			
		||||
                    mockLocation,
 | 
			
		||||
                    mockObjectService,
 | 
			
		||||
                    mockNavigationService
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockScope.backArrow();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@
 | 
			
		||||
                "glyph": "Z",
 | 
			
		||||
                "name": "Remove",
 | 
			
		||||
                "description": "Remove this object from its containing object.",
 | 
			
		||||
                "depends": [ "$q" ]
 | 
			
		||||
                "depends": [ "$q", "navigationService" ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "save",
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ define(
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @memberof module:editor/actions/remove-action
 | 
			
		||||
         */
 | 
			
		||||
        function RemoveAction($q, context) {
 | 
			
		||||
        function RemoveAction($q, navigationService, context) {
 | 
			
		||||
            var object = (context || {}).domainObject;
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
@@ -69,14 +69,25 @@ define(
 | 
			
		||||
                return persistence && persistence.persist();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Checks current object with object being removed
 | 
			
		||||
            function checkCurrentObjectNavigation(object, parent) {
 | 
			
		||||
                var currentObj = navigationService.getNavigation();
 | 
			
		||||
                if (currentObj.getId() === object.getId()) {
 | 
			
		||||
                    navigationService.setNavigation(parent);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            /**
 | 
			
		||||
             * Remove the object from its parent, as identified by its context
 | 
			
		||||
             * capability.
 | 
			
		||||
             * @param {ContextCapability} contextCapability the "context" capability
 | 
			
		||||
             *        of the domain object being removed.
 | 
			
		||||
             * @param {object} domain object being removed contextCapability
 | 
			
		||||
                      gotten from the "context" capability of this object
 | 
			
		||||
             */
 | 
			
		||||
            function removeFromContext(contextCapability) {
 | 
			
		||||
                var parent = contextCapability.getParent();
 | 
			
		||||
            function removeFromContext(object) {
 | 
			
		||||
                var contextCapability = object.getCapability('context'),
 | 
			
		||||
                    parent = contextCapability.getParent();
 | 
			
		||||
                // Navigates to parent if deleting current object
 | 
			
		||||
                checkCurrentObjectNavigation(object, parent);
 | 
			
		||||
                $q.when(
 | 
			
		||||
                    parent.useCapability('mutation', doMutate)
 | 
			
		||||
                ).then(function () {
 | 
			
		||||
@@ -91,7 +102,7 @@ define(
 | 
			
		||||
                 *         fulfilled when the action has completed.
 | 
			
		||||
                 */
 | 
			
		||||
                perform: function () {
 | 
			
		||||
                    return $q.when(object.getCapability('context'))
 | 
			
		||||
                    return $q.when(object)
 | 
			
		||||
                        .then(removeFromContext);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ define(
 | 
			
		||||
 | 
			
		||||
        describe("The Remove action", function () {
 | 
			
		||||
            var mockQ,
 | 
			
		||||
                mockNavigationService,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockParent,
 | 
			
		||||
                mockContext,
 | 
			
		||||
@@ -64,19 +65,32 @@ define(
 | 
			
		||||
                    },
 | 
			
		||||
                    useCapability: function (k, v) {
 | 
			
		||||
                        return capabilities[k].invoke(v);
 | 
			
		||||
                    },
 | 
			
		||||
                    getId: function () {
 | 
			
		||||
                        return "test";
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                mockContext = jasmine.createSpyObj("context", [ "getParent" ]);
 | 
			
		||||
                mockMutation = jasmine.createSpyObj("mutation", [ "invoke" ]);
 | 
			
		||||
                mockPersistence = jasmine.createSpyObj("persistence", [ "persist" ]);
 | 
			
		||||
                mockType = jasmine.createSpyObj("type", [ "hasFeature" ]);
 | 
			
		||||
 | 
			
		||||
                mockNavigationService = jasmine.createSpyObj(
 | 
			
		||||
                    "navigationService",
 | 
			
		||||
                    [
 | 
			
		||||
                        "getNavigation",
 | 
			
		||||
                        "setNavigation",
 | 
			
		||||
                        "addListener",
 | 
			
		||||
                        "removeListener"
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                mockNavigationService.getNavigation.andReturn(mockDomainObject);
 | 
			
		||||
                
 | 
			
		||||
                
 | 
			
		||||
                mockDomainObject.getId.andReturn("test");
 | 
			
		||||
                mockDomainObject.getCapability.andReturn(mockContext);
 | 
			
		||||
                mockContext.getParent.andReturn(mockParent);
 | 
			
		||||
                mockType.hasFeature.andReturn(true);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                capabilities = {
 | 
			
		||||
                    mutation: mockMutation,
 | 
			
		||||
                    persistence: mockPersistence,
 | 
			
		||||
@@ -88,7 +102,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                actionContext = { domainObject: mockDomainObject };
 | 
			
		||||
 | 
			
		||||
                action = new RemoveAction(mockQ, actionContext);
 | 
			
		||||
                action = new RemoveAction(mockQ, mockNavigationService, actionContext);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("only applies to objects with parents", function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,11 @@
 | 
			
		||||
                "key": "urlService",
 | 
			
		||||
                "implementation": "/services/UrlService.js",
 | 
			
		||||
                "depends": [ "$location" ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "agentService",
 | 
			
		||||
                "implementation": "/services/AgentService.js",
 | 
			
		||||
                "depends": [ "$window" ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "runs": [
 | 
			
		||||
@@ -60,7 +65,7 @@
 | 
			
		||||
            {
 | 
			
		||||
                "key": "TreeNodeController",
 | 
			
		||||
                "implementation": "controllers/TreeNodeController.js",
 | 
			
		||||
                "depends": [ "$scope", "$timeout" ]
 | 
			
		||||
                "depends": [ "$scope", "$timeout", "agentService" ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "ActionGroupController",
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,33 @@
 | 
			
		||||
/************************** CONTROLS */
 | 
			
		||||
/************************** PATHS */
 | 
			
		||||
/************************** TIMINGS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
 | 
			
		||||
/************************** MOBILE TREE MENU DIMENSIONS */
 | 
			
		||||
/************************** WINDOW DIMENSIONS FOR RWD */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -120,6 +147,27 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/* line 22, ../sass/forms/_elems.scss */
 | 
			
		||||
.section-header {
 | 
			
		||||
  -moz-border-radius: 3px;
 | 
			
		||||
@@ -392,7 +440,7 @@ input[type="text"] {
 | 
			
		||||
  margin: 0 0 2px 2px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  position: relative; }
 | 
			
		||||
  /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
  .form-control.select:not(.disabled):hover {
 | 
			
		||||
    background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
 | 
			
		||||
    background-size: 100%;
 | 
			
		||||
@@ -401,10 +449,10 @@ input[type="text"] {
 | 
			
		||||
    background-image: -webkit-linear-gradient(#636363, #575757);
 | 
			
		||||
    background-image: linear-gradient(#636363, #575757);
 | 
			
		||||
    color: #bdbdbd; }
 | 
			
		||||
    /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
    .form-control.select:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
      color: #878787; }
 | 
			
		||||
  /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
  .form-control.select.btn-menu .invoke-menu {
 | 
			
		||||
    color: #757575; }
 | 
			
		||||
  /* line 29, ../sass/forms/_selects.scss */
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,33 @@
 | 
			
		||||
/************************** CONTROLS */
 | 
			
		||||
/************************** PATHS */
 | 
			
		||||
/************************** TIMINGS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
 | 
			
		||||
/************************** MOBILE TREE MENU DIMENSIONS */
 | 
			
		||||
/************************** WINDOW DIMENSIONS FOR RWD */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -78,6 +105,27 @@
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -136,7 +184,7 @@
 | 
			
		||||
    margin-bottom: 3px;
 | 
			
		||||
    margin-right: 3px;
 | 
			
		||||
    position: relative; }
 | 
			
		||||
    /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
    .items-holder .item.grid-item:not(.disabled):hover {
 | 
			
		||||
      background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzcwNzA3MCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
 | 
			
		||||
      background-size: 100%;
 | 
			
		||||
@@ -145,10 +193,10 @@
 | 
			
		||||
      background-image: -webkit-linear-gradient(#707070, #636363);
 | 
			
		||||
      background-image: linear-gradient(#707070, #636363);
 | 
			
		||||
      color: #bdbdbd; }
 | 
			
		||||
      /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
      .items-holder .item.grid-item:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
        color: #949494; }
 | 
			
		||||
    /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
    .items-holder .item.grid-item.btn-menu .invoke-menu {
 | 
			
		||||
      color: #828282; }
 | 
			
		||||
    /* line 46, ../sass/items/_item.scss */
 | 
			
		||||
@@ -269,7 +317,7 @@
 | 
			
		||||
      color: #999;
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      color: #80dfff; }
 | 
			
		||||
      /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
      .items-holder .item.grid-item.selected:not(.disabled):hover {
 | 
			
		||||
        background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzJlY2JmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzE0YzRmZiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
 | 
			
		||||
        background-size: 100%;
 | 
			
		||||
@@ -278,10 +326,10 @@
 | 
			
		||||
        background-image: -webkit-linear-gradient(#2ecbff, #14c4ff);
 | 
			
		||||
        background-image: linear-gradient(#2ecbff, #14c4ff);
 | 
			
		||||
        color: #bdbdbd; }
 | 
			
		||||
        /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
        /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
        .items-holder .item.grid-item.selected:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
          color: #75ddff; }
 | 
			
		||||
      /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
      .items-holder .item.grid-item.selected.btn-menu .invoke-menu {
 | 
			
		||||
        color: #52d4ff; }
 | 
			
		||||
      /* line 140, ../sass/items/_item.scss */
 | 
			
		||||
@@ -296,3 +344,105 @@
 | 
			
		||||
      /* line 144, ../sass/items/_item.scss */
 | 
			
		||||
      .items-holder .item.grid-item.selected:hover .item-main .item-type {
 | 
			
		||||
        color: white !important; }
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 34, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item .mobile-grid-nav {
 | 
			
		||||
    top: 0px;
 | 
			
		||||
    bottom: 0px;
 | 
			
		||||
    right: 55px; }
 | 
			
		||||
  /* line 39, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item .mobile-info {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    width: 50px;
 | 
			
		||||
    right: 0px;
 | 
			
		||||
    left: auto;
 | 
			
		||||
    font-size: 1.3em; }
 | 
			
		||||
  /* line 47, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item .bar.bottom-bar.abs {
 | 
			
		||||
    top: 0px;
 | 
			
		||||
    height: auto; }
 | 
			
		||||
  /* line 54, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item .item-main .item-type {
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
    top: 0px;
 | 
			
		||||
    left: 0px;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
    height: auto; }
 | 
			
		||||
  /* line 61, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item .item-main .item-open {
 | 
			
		||||
    display: none; }
 | 
			
		||||
  /* line 65, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item .title, .items-holder .item.grid-item .details {
 | 
			
		||||
    margin-left: 30px; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 29, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 50px; }
 | 
			
		||||
    /* line 74, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .mobile-right {
 | 
			
		||||
      top: 100%; }
 | 
			
		||||
    /* line 77, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .mobile-info {
 | 
			
		||||
      line-height: 25px; }
 | 
			
		||||
    /* line 81, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .item-main .item-type {
 | 
			
		||||
      line-height: 40px; }
 | 
			
		||||
    /* line 85, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .title {
 | 
			
		||||
      margin-right: 10px;
 | 
			
		||||
      line-height: 25px; }
 | 
			
		||||
    /* line 89, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .details {
 | 
			
		||||
      margin-right: 10px;
 | 
			
		||||
      line-height: 0px; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 29, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 66.66667px; }
 | 
			
		||||
    /* line 99, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .mobile-right {
 | 
			
		||||
      top: 100%; }
 | 
			
		||||
    /* line 103, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .mobile-info {
 | 
			
		||||
      line-height: 38px; }
 | 
			
		||||
    /* line 107, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .item-main .item-type {
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      line-height: 50px; }
 | 
			
		||||
    /* line 112, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .title {
 | 
			
		||||
      margin-right: 10px;
 | 
			
		||||
      line-height: 38px; }
 | 
			
		||||
    /* line 116, ../sass/mobile/_item.scss */
 | 
			
		||||
    .items-holder .item.grid-item .details {
 | 
			
		||||
      margin-right: 10px;
 | 
			
		||||
      line-height: 0px; } }
 | 
			
		||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
  /* line 29, ../sass/mobile/_item.scss */
 | 
			
		||||
  .items-holder .item.grid-item {
 | 
			
		||||
    width: 200px;
 | 
			
		||||
    height: 200px; } }
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,33 @@
 | 
			
		||||
/************************** CONTROLS */
 | 
			
		||||
/************************** PATHS */
 | 
			
		||||
/************************** TIMINGS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
 | 
			
		||||
/************************** MOBILE TREE MENU DIMENSIONS */
 | 
			
		||||
/************************** WINDOW DIMENSIONS FOR RWD */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -92,7 +119,7 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/* line 5, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
html, body, div, span, applet, object, iframe,
 | 
			
		||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
 | 
			
		||||
a, abbr, acronym, address, big, cite, code,
 | 
			
		||||
@@ -113,38 +140,38 @@ time, mark, audio, video {
 | 
			
		||||
  font-size: 100%;
 | 
			
		||||
  vertical-align: baseline; }
 | 
			
		||||
 | 
			
		||||
/* line 22, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
html {
 | 
			
		||||
  line-height: 1; }
 | 
			
		||||
 | 
			
		||||
/* line 24, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
ol, ul {
 | 
			
		||||
  list-style: none; }
 | 
			
		||||
 | 
			
		||||
/* line 26, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
table {
 | 
			
		||||
  border-collapse: collapse;
 | 
			
		||||
  border-spacing: 0; }
 | 
			
		||||
 | 
			
		||||
/* line 28, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
caption, th, td {
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  vertical-align: middle; }
 | 
			
		||||
 | 
			
		||||
/* line 30, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
q, blockquote {
 | 
			
		||||
  quotes: none; }
 | 
			
		||||
  /* line 103, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
  /* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
  q:before, q:after, blockquote:before, blockquote:after {
 | 
			
		||||
    content: "";
 | 
			
		||||
    content: none; }
 | 
			
		||||
 | 
			
		||||
/* line 32, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
a img {
 | 
			
		||||
  border: none; }
 | 
			
		||||
 | 
			
		||||
/* line 116, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
 | 
			
		||||
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
 | 
			
		||||
  display: block; }
 | 
			
		||||
 | 
			
		||||
@@ -178,6 +205,27 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -664,21 +712,251 @@ mct-container {
 | 
			
		||||
/* line 267, ../sass/user-environ/_layout.scss */
 | 
			
		||||
.split-layout.vertical > .pane {
 | 
			
		||||
  margin-left: 5px; }
 | 
			
		||||
  /* line 269, ../sass/user-environ/_layout.scss */
 | 
			
		||||
  /* line 270, ../sass/user-environ/_layout.scss */
 | 
			
		||||
  .split-layout.vertical > .pane > .holder {
 | 
			
		||||
    left: 0;
 | 
			
		||||
    right: 0; }
 | 
			
		||||
  /* line 273, ../sass/user-environ/_layout.scss */
 | 
			
		||||
  /* line 274, ../sass/user-environ/_layout.scss */
 | 
			
		||||
  .split-layout.vertical > .pane:first-child {
 | 
			
		||||
    margin-left: 0; }
 | 
			
		||||
    /* line 275, ../sass/user-environ/_layout.scss */
 | 
			
		||||
    /* line 276, ../sass/user-environ/_layout.scss */
 | 
			
		||||
    .split-layout.vertical > .pane:first-child .holder {
 | 
			
		||||
      right: 3px; }
 | 
			
		||||
 | 
			
		||||
/* line 284, ../sass/user-environ/_layout.scss */
 | 
			
		||||
/* line 285, ../sass/user-environ/_layout.scss */
 | 
			
		||||
.vscroll {
 | 
			
		||||
  overflow-y: auto; }
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 26, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-wrapper,
 | 
			
		||||
  .mobile-pane {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    white-space: nowrap; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
  /* line 38, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .desktop-browse {
 | 
			
		||||
    min-width: 150px;
 | 
			
		||||
    max-width: 800px;
 | 
			
		||||
    width: 25%; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 49, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-hidetree {
 | 
			
		||||
    -moz-user-select: -moz-none;
 | 
			
		||||
    -ms-user-select: none;
 | 
			
		||||
    -webkit-user-select: none;
 | 
			
		||||
    user-select: none; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 60, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-hidetree .mobile-pane.left-menu {
 | 
			
		||||
    -moz-transition-property: opacity;
 | 
			
		||||
    -o-transition-property: opacity;
 | 
			
		||||
    -webkit-transition-property: opacity;
 | 
			
		||||
    transition-property: opacity;
 | 
			
		||||
    -moz-transition-duration: 0.4s;
 | 
			
		||||
    -o-transition-duration: 0.4s;
 | 
			
		||||
    -webkit-transition-duration: 0.4s;
 | 
			
		||||
    transition-duration: 0.4s;
 | 
			
		||||
    -moz-transition-timing-function: ease-in-out;
 | 
			
		||||
    -o-transition-timing-function: ease-in-out;
 | 
			
		||||
    -webkit-transition-timing-function: ease-in-out;
 | 
			
		||||
    transition-timing-function: ease-in-out;
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    right: 100% !important;
 | 
			
		||||
    width: auto !important;
 | 
			
		||||
    overflow-y: hidden;
 | 
			
		||||
    overflow-x: hidden; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 73, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-hidetree .mobile-pane.right-repr {
 | 
			
		||||
    -moz-transition-duration: 0.35s;
 | 
			
		||||
    -o-transition-duration: 0.35s;
 | 
			
		||||
    -webkit-transition-duration: 0.35s;
 | 
			
		||||
    transition-duration: 0.35s;
 | 
			
		||||
    transition-timing-function: ease;
 | 
			
		||||
    backface-visibility: hidden;
 | 
			
		||||
    left: auto !important;
 | 
			
		||||
    width: 100% !important; } }
 | 
			
		||||
 | 
			
		||||
/* line 82, ../sass/mobile/_layout.scss */
 | 
			
		||||
.mobile-tree-holder {
 | 
			
		||||
  top: 30px; }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 91, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree {
 | 
			
		||||
    -moz-user-select: -moz-none;
 | 
			
		||||
    -ms-user-select: none;
 | 
			
		||||
    -webkit-user-select: none;
 | 
			
		||||
    user-select: none; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 102, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.left-menu {
 | 
			
		||||
    -moz-transition-property: opacity;
 | 
			
		||||
    -o-transition-property: opacity;
 | 
			
		||||
    -webkit-transition-property: opacity;
 | 
			
		||||
    transition-property: opacity;
 | 
			
		||||
    -moz-transition-duration: 0.4s;
 | 
			
		||||
    -o-transition-duration: 0.4s;
 | 
			
		||||
    -webkit-transition-duration: 0.4s;
 | 
			
		||||
    transition-duration: 0.4s;
 | 
			
		||||
    -moz-transition-timing-function: ease-in-out;
 | 
			
		||||
    -o-transition-timing-function: ease-in-out;
 | 
			
		||||
    -webkit-transition-timing-function: ease-in-out;
 | 
			
		||||
    transition-timing-function: ease-in-out;
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
    display: block !important;
 | 
			
		||||
    width: auto !important; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
 | 
			
		||||
  /* line 102, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.left-menu {
 | 
			
		||||
    right: 19px !important; } }
 | 
			
		||||
@media screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 102, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.left-menu {
 | 
			
		||||
    right: 66% !important; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px) {
 | 
			
		||||
  /* line 102, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.left-menu {
 | 
			
		||||
    right: 500px !important; } }
 | 
			
		||||
@media screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 102, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.left-menu {
 | 
			
		||||
    right: 78% !important; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 126, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.right-repr {
 | 
			
		||||
    -moz-transition-duration: 0.35s;
 | 
			
		||||
    -o-transition-duration: 0.35s;
 | 
			
		||||
    -webkit-transition-duration: 0.35s;
 | 
			
		||||
    transition-duration: 0.35s;
 | 
			
		||||
    transition-timing-function: ease;
 | 
			
		||||
    backface-visibility: hidden;
 | 
			
		||||
    left: auto !important; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
 | 
			
		||||
  /* line 126, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.right-repr {
 | 
			
		||||
    width: 19px !important; } }
 | 
			
		||||
@media screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 126, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.right-repr {
 | 
			
		||||
    width: 66% !important; } }
 | 
			
		||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px) {
 | 
			
		||||
  /* line 126, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.right-repr {
 | 
			
		||||
    width: 500px !important; } }
 | 
			
		||||
@media screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 126, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .browse-showtree .mobile-pane.right-repr {
 | 
			
		||||
    width: 78% !important; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 149, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .button-pos {
 | 
			
		||||
    position: absolute; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 158, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .object-header {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    left: 44px; }
 | 
			
		||||
    /* line 163, ../sass/mobile/_layout.scss */
 | 
			
		||||
    .object-header .label .context-available {
 | 
			
		||||
      opacity: 1 !important; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
  /* line 170, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .desktop-hide {
 | 
			
		||||
    display: none; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 177, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .mobile-hide {
 | 
			
		||||
    display: none; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 183, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .mobile-important-hide {
 | 
			
		||||
    display: none !important; } }
 | 
			
		||||
 | 
			
		||||
/* line 189, ../sass/mobile/_layout.scss */
 | 
			
		||||
.mobile-back-hide {
 | 
			
		||||
  pointer-events: none;
 | 
			
		||||
  -moz-transition-property: opacity;
 | 
			
		||||
  -o-transition-property: opacity;
 | 
			
		||||
  -webkit-transition-property: opacity;
 | 
			
		||||
  transition-property: opacity;
 | 
			
		||||
  -moz-transition-duration: 0.4s;
 | 
			
		||||
  -o-transition-duration: 0.4s;
 | 
			
		||||
  -webkit-transition-duration: 0.4s;
 | 
			
		||||
  transition-duration: 0.4s;
 | 
			
		||||
  -moz-transition-timing-function: ease-in-out;
 | 
			
		||||
  -o-transition-timing-function: ease-in-out;
 | 
			
		||||
  -webkit-transition-timing-function: ease-in-out;
 | 
			
		||||
  transition-timing-function: ease-in-out;
 | 
			
		||||
  opacity: 0; }
 | 
			
		||||
 | 
			
		||||
/* line 196, ../sass/mobile/_layout.scss */
 | 
			
		||||
.mobile-back-unhide {
 | 
			
		||||
  pointer-events: all;
 | 
			
		||||
  -moz-transition-property: opacity;
 | 
			
		||||
  -o-transition-property: opacity;
 | 
			
		||||
  -webkit-transition-property: opacity;
 | 
			
		||||
  transition-property: opacity;
 | 
			
		||||
  -moz-transition-duration: 0.4s;
 | 
			
		||||
  -o-transition-duration: 0.4s;
 | 
			
		||||
  -webkit-transition-duration: 0.4s;
 | 
			
		||||
  transition-duration: 0.4s;
 | 
			
		||||
  -moz-transition-timing-function: ease-in-out;
 | 
			
		||||
  -o-transition-timing-function: ease-in-out;
 | 
			
		||||
  -webkit-transition-timing-function: ease-in-out;
 | 
			
		||||
  transition-timing-function: ease-in-out;
 | 
			
		||||
  opacity: 1; }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 203, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .phone-hide {
 | 
			
		||||
    display: none; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 209, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .tree-holder {
 | 
			
		||||
    overflow-x: hidden !important; } }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 214, ../sass/mobile/_layout.scss */
 | 
			
		||||
  .mobile-disable-select {
 | 
			
		||||
    -moz-user-select: -moz-none;
 | 
			
		||||
    -ms-user-select: none;
 | 
			
		||||
    -webkit-user-select: none;
 | 
			
		||||
    user-select: none; } }
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
* as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -1452,7 +1730,7 @@ mct-container {
 | 
			
		||||
    color: #999;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    color: #ccf2ff; }
 | 
			
		||||
    /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
    .btn.major:not(.disabled):hover,
 | 
			
		||||
    .s-btn.major:not(.disabled):hover,
 | 
			
		||||
    .major.icon-btn:not(.disabled):hover,
 | 
			
		||||
@@ -1464,13 +1742,13 @@ mct-container {
 | 
			
		||||
      background-image: -webkit-linear-gradient(#2ecbff, #14c4ff);
 | 
			
		||||
      background-image: linear-gradient(#2ecbff, #14c4ff);
 | 
			
		||||
      color: #bdbdbd; }
 | 
			
		||||
      /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
      .btn.major:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .s-btn.major:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .major.icon-btn:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .major.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
        color: #75ddff; }
 | 
			
		||||
    /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
    .btn.major.btn-menu .invoke-menu,
 | 
			
		||||
    .s-btn.major.btn-menu .invoke-menu,
 | 
			
		||||
    .major.btn-menu.icon-btn .invoke-menu,
 | 
			
		||||
@@ -1500,7 +1778,7 @@ mct-container {
 | 
			
		||||
      border-top: 1px solid #2ecbff;
 | 
			
		||||
      color: #ccf2ff;
 | 
			
		||||
      display: inline-block; }
 | 
			
		||||
      /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
      .btn.major:hover:not(.disabled):hover,
 | 
			
		||||
      .s-btn.major:hover:not(.disabled):hover,
 | 
			
		||||
      .major.icon-btn:hover:not(.disabled):hover,
 | 
			
		||||
@@ -1512,13 +1790,13 @@ mct-container {
 | 
			
		||||
        background-image: -webkit-linear-gradient(#47d1ff, #2ecbff);
 | 
			
		||||
        background-image: linear-gradient(#47d1ff, #2ecbff);
 | 
			
		||||
        color: white; }
 | 
			
		||||
        /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
        /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
        .btn.major:hover:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
        .s-btn.major:hover:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
        .major.icon-btn:hover:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
        .major.s-icon-btn:hover:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
          color: #8fe3ff; }
 | 
			
		||||
      /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
      .btn.major:hover.btn-menu .invoke-menu,
 | 
			
		||||
      .s-btn.major:hover.btn-menu .invoke-menu,
 | 
			
		||||
      .major.icon-btn:hover.btn-menu .invoke-menu,
 | 
			
		||||
@@ -1554,7 +1832,7 @@ mct-container {
 | 
			
		||||
    border-top: 1px solid #8a8a8a;
 | 
			
		||||
    color: #cccccc;
 | 
			
		||||
    display: inline-block; }
 | 
			
		||||
    /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
    .btn.subtle:not(.disabled):hover,
 | 
			
		||||
    .s-btn.subtle:not(.disabled):hover,
 | 
			
		||||
    .subtle.icon-btn:not(.disabled):hover,
 | 
			
		||||
@@ -1566,13 +1844,13 @@ mct-container {
 | 
			
		||||
      background-image: -webkit-linear-gradient(#969696, #8a8a8a);
 | 
			
		||||
      background-image: linear-gradient(#969696, #8a8a8a);
 | 
			
		||||
      color: #f0f0f0; }
 | 
			
		||||
      /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
      .btn.subtle:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .s-btn.subtle:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .subtle.icon-btn:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .subtle.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
        color: #bababa; }
 | 
			
		||||
    /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
    .btn.subtle.btn-menu .invoke-menu,
 | 
			
		||||
    .s-btn.subtle.btn-menu .invoke-menu,
 | 
			
		||||
    .subtle.btn-menu.icon-btn .invoke-menu,
 | 
			
		||||
@@ -1605,7 +1883,7 @@ mct-container {
 | 
			
		||||
    border-top: 1px solid #575757;
 | 
			
		||||
    color: #999;
 | 
			
		||||
    display: inline-block; }
 | 
			
		||||
    /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
    .btn.very-subtle:not(.disabled):hover, .btn.s-very-subtle:not(.disabled):hover,
 | 
			
		||||
    .s-btn.very-subtle:not(.disabled):hover,
 | 
			
		||||
    .very-subtle.icon-btn:not(.disabled):hover,
 | 
			
		||||
@@ -1620,7 +1898,7 @@ mct-container {
 | 
			
		||||
      background-image: -webkit-linear-gradient(#636363, #575757);
 | 
			
		||||
      background-image: linear-gradient(#636363, #575757);
 | 
			
		||||
      color: #bdbdbd; }
 | 
			
		||||
      /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
      .btn.very-subtle:not(.disabled):hover.btn-menu .invoke-menu, .btn.s-very-subtle:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .s-btn.very-subtle:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .very-subtle.icon-btn:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
@@ -1629,7 +1907,7 @@ mct-container {
 | 
			
		||||
      .s-very-subtle.icon-btn:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
      .s-very-subtle.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
        color: #878787; }
 | 
			
		||||
    /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
    .btn.very-subtle.btn-menu .invoke-menu, .btn.s-very-subtle.btn-menu .invoke-menu,
 | 
			
		||||
    .s-btn.very-subtle.btn-menu .invoke-menu,
 | 
			
		||||
    .very-subtle.btn-menu.icon-btn .invoke-menu,
 | 
			
		||||
@@ -1665,7 +1943,7 @@ mct-container {
 | 
			
		||||
      border-top: 1px solid #fe9510;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      display: inline-block; }
 | 
			
		||||
      /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
      .btn.very-subtle.paused:not(.disabled):hover, .btn.s-very-subtle.paused:not(.disabled):hover,
 | 
			
		||||
      .s-btn.very-subtle.paused:not(.disabled):hover,
 | 
			
		||||
      .very-subtle.paused.icon-btn:not(.disabled):hover,
 | 
			
		||||
@@ -1680,7 +1958,7 @@ mct-container {
 | 
			
		||||
        background-image: -webkit-linear-gradient(#fea029, #fe9510);
 | 
			
		||||
        background-image: linear-gradient(#fea029, #fe9510);
 | 
			
		||||
        color: white; }
 | 
			
		||||
        /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
        /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
        .btn.very-subtle.paused:not(.disabled):hover.btn-menu .invoke-menu, .btn.s-very-subtle.paused:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
        .s-btn.very-subtle.paused:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
        .very-subtle.paused.icon-btn:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
@@ -1689,7 +1967,7 @@ mct-container {
 | 
			
		||||
        .s-very-subtle.paused.icon-btn:not(.disabled):hover.btn-menu .invoke-menu,
 | 
			
		||||
        .s-very-subtle.paused.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
          color: #fec070; }
 | 
			
		||||
      /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
      .btn.very-subtle.paused.btn-menu .invoke-menu, .btn.s-very-subtle.paused.btn-menu .invoke-menu,
 | 
			
		||||
      .s-btn.very-subtle.paused.btn-menu .invoke-menu,
 | 
			
		||||
      .very-subtle.paused.btn-menu.icon-btn .invoke-menu,
 | 
			
		||||
@@ -2141,7 +2419,7 @@ label.checkbox.custom {
 | 
			
		||||
  			color: lighten($c, 10%);
 | 
			
		||||
  		}
 | 
			
		||||
  	}*/ }
 | 
			
		||||
  /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
  .btn-menu:not(.disabled):hover {
 | 
			
		||||
    background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
 | 
			
		||||
    background-size: 100%;
 | 
			
		||||
@@ -2150,10 +2428,10 @@ label.checkbox.custom {
 | 
			
		||||
    background-image: -webkit-linear-gradient(#636363, #575757);
 | 
			
		||||
    background-image: linear-gradient(#636363, #575757);
 | 
			
		||||
    color: #bdbdbd; }
 | 
			
		||||
    /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
    .btn-menu:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
      color: #878787; }
 | 
			
		||||
  /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
  .btn-menu.btn-menu .invoke-menu {
 | 
			
		||||
    color: #757575; }
 | 
			
		||||
  /* line 285, ../sass/controls/_controls.scss */
 | 
			
		||||
@@ -2299,7 +2577,7 @@ label.checkbox.custom {
 | 
			
		||||
  auto: 0;
 | 
			
		||||
  bottom: auto;
 | 
			
		||||
  left: auto; }
 | 
			
		||||
  /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
  .slider .knob:not(.disabled):hover {
 | 
			
		||||
    background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
 | 
			
		||||
    background-size: 100%;
 | 
			
		||||
@@ -2308,13 +2586,13 @@ label.checkbox.custom {
 | 
			
		||||
    background-image: -webkit-linear-gradient(#636363, #575757);
 | 
			
		||||
    background-image: linear-gradient(#636363, #575757);
 | 
			
		||||
    color: #bdbdbd; }
 | 
			
		||||
    /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
    .slider .knob:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
      color: #878787; }
 | 
			
		||||
  /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
  .slider .knob.btn-menu .invoke-menu {
 | 
			
		||||
    color: #757575; }
 | 
			
		||||
  /* line 186, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 187, ../sass/_mixins.scss */
 | 
			
		||||
  .slider .knob:before {
 | 
			
		||||
    -moz-transition-property: "border-color";
 | 
			
		||||
    -o-transition-property: "border-color";
 | 
			
		||||
@@ -2338,7 +2616,7 @@ label.checkbox.custom {
 | 
			
		||||
    left: 2px;
 | 
			
		||||
    bottom: 5px;
 | 
			
		||||
    top: 5px; }
 | 
			
		||||
  /* line 208, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 209, ../sass/_mixins.scss */
 | 
			
		||||
  .slider .knob:not(.disabled):hover:before {
 | 
			
		||||
    -moz-transition-property: "border-color";
 | 
			
		||||
    -o-transition-property: "border-color";
 | 
			
		||||
@@ -2510,14 +2788,14 @@ label.checkbox.custom {
 | 
			
		||||
    padding: 3px 0;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 10; }
 | 
			
		||||
    /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
    .menu-element .menu.btn-menu .invoke-menu {
 | 
			
		||||
      color: #828282; }
 | 
			
		||||
    /* line 37, ../sass/controls/_menus.scss */
 | 
			
		||||
    .menu-element .menu ul {
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      padding: 0; }
 | 
			
		||||
      /* line 276, ../sass/_mixins.scss */
 | 
			
		||||
      /* line 277, ../sass/_mixins.scss */
 | 
			
		||||
      .menu-element .menu ul li {
 | 
			
		||||
        list-style-type: none;
 | 
			
		||||
        margin: 0;
 | 
			
		||||
@@ -2568,7 +2846,7 @@ label.checkbox.custom {
 | 
			
		||||
    border-top: 1px solid #919191;
 | 
			
		||||
    color: #999;
 | 
			
		||||
    display: inline-block; }
 | 
			
		||||
    /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
    .menu-element .context-menu.btn-menu .invoke-menu,
 | 
			
		||||
    .menu-element .super-menu.btn-menu .invoke-menu {
 | 
			
		||||
      color: #b0b0b0; }
 | 
			
		||||
@@ -2686,6 +2964,40 @@ label.checkbox.custom {
 | 
			
		||||
  right: 0;
 | 
			
		||||
  width: auto; }
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/* line 25, ../sass/mobile/controls/_menus.scss */
 | 
			
		||||
.mobile-menu-icon {
 | 
			
		||||
  display: inline-block; }
 | 
			
		||||
  @media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
    /* line 25, ../sass/mobile/controls/_menus.scss */
 | 
			
		||||
    .mobile-menu-icon {
 | 
			
		||||
      font-size: 21px;
 | 
			
		||||
      padding-top: 1px; } }
 | 
			
		||||
  @media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
    /* line 25, ../sass/mobile/controls/_menus.scss */
 | 
			
		||||
    .mobile-menu-icon {
 | 
			
		||||
      display: none; } }
 | 
			
		||||
 | 
			
		||||
/* line 1, ../sass/controls/_time-controller.scss */
 | 
			
		||||
.l-time-controller {
 | 
			
		||||
  position: relative;
 | 
			
		||||
@@ -3442,7 +3754,7 @@ input[type="text"] {
 | 
			
		||||
  margin: 0 0 2px 2px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  position: relative; }
 | 
			
		||||
  /* line 162, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 163, ../sass/_mixins.scss */
 | 
			
		||||
  .form-control.select:not(.disabled):hover {
 | 
			
		||||
    background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
 | 
			
		||||
    background-size: 100%;
 | 
			
		||||
@@ -3451,10 +3763,10 @@ input[type="text"] {
 | 
			
		||||
    background-image: -webkit-linear-gradient(#636363, #575757);
 | 
			
		||||
    background-image: linear-gradient(#636363, #575757);
 | 
			
		||||
    color: #bdbdbd; }
 | 
			
		||||
    /* line 165, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 166, ../sass/_mixins.scss */
 | 
			
		||||
    .form-control.select:not(.disabled):hover.btn-menu .invoke-menu {
 | 
			
		||||
      color: #878787; }
 | 
			
		||||
  /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
  .form-control.select.btn-menu .invoke-menu {
 | 
			
		||||
    color: #757575; }
 | 
			
		||||
  /* line 29, ../sass/forms/_selects.scss */
 | 
			
		||||
@@ -4073,7 +4385,7 @@ input[type="text"] {
 | 
			
		||||
  bottom: 15%;
 | 
			
		||||
  left: 15%;
 | 
			
		||||
  z-index: 101; }
 | 
			
		||||
  /* line 170, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 171, ../sass/_mixins.scss */
 | 
			
		||||
  .overlay > .holder.btn-menu .invoke-menu {
 | 
			
		||||
    color: #757575; }
 | 
			
		||||
  /* line 45, ../sass/overlay/_overlay.scss */
 | 
			
		||||
@@ -4118,6 +4430,17 @@ input[type="text"] {
 | 
			
		||||
  left: 5px;
 | 
			
		||||
  overflow: auto; }
 | 
			
		||||
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 6, ../sass/mobile/overlay/_overlay.scss */
 | 
			
		||||
  .overlay > .holder {
 | 
			
		||||
    -moz-border-radius: 0;
 | 
			
		||||
    -webkit-border-radius: 0;
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0; } }
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -4443,33 +4766,40 @@ input[type="text"] {
 | 
			
		||||
    margin-left: 20px; }
 | 
			
		||||
    /* line 80, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
    .l-infobubble-wrapper.arw-left .l-infobubble::before {
 | 
			
		||||
      right: 100%;
 | 
			
		||||
      width: 0;
 | 
			
		||||
      height: 0;
 | 
			
		||||
      border-top: 6.66667px solid transparent;
 | 
			
		||||
      border-bottom: 6.66667px solid transparent;
 | 
			
		||||
      border-right: 10px solid #ddd; }
 | 
			
		||||
  /* line 86, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .l-infobubble-wrapper.arw-right {
 | 
			
		||||
    margin-right: 20px; }
 | 
			
		||||
    /* line 88, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
    .l-infobubble-wrapper.arw-right .l-infobubble::before {
 | 
			
		||||
      left: 100%;
 | 
			
		||||
      width: 0;
 | 
			
		||||
      height: 0;
 | 
			
		||||
      border-top: 6.66667px solid transparent;
 | 
			
		||||
      border-bottom: 6.66667px solid transparent;
 | 
			
		||||
      border-left: 10px solid #ddd; }
 | 
			
		||||
  /* line 95, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
      right: 100%; }
 | 
			
		||||
      @media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
        /* line 80, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
        .l-infobubble-wrapper.arw-left .l-infobubble::before {
 | 
			
		||||
          width: 0;
 | 
			
		||||
          height: 0;
 | 
			
		||||
          border-top: 6.66667px solid transparent;
 | 
			
		||||
          border-bottom: 6.66667px solid transparent;
 | 
			
		||||
          border-right: 10px solid #ddd; } }
 | 
			
		||||
  @media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
    /* line 92, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
    .l-infobubble-wrapper.arw-right {
 | 
			
		||||
      margin-right: 20px; } }
 | 
			
		||||
  /* line 99, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .l-infobubble-wrapper.arw-right .l-infobubble::before {
 | 
			
		||||
    left: 100%; }
 | 
			
		||||
    @media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
      /* line 99, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
      .l-infobubble-wrapper.arw-right .l-infobubble::before {
 | 
			
		||||
        width: 0;
 | 
			
		||||
        height: 0;
 | 
			
		||||
        border-top: 6.66667px solid transparent;
 | 
			
		||||
        border-bottom: 6.66667px solid transparent;
 | 
			
		||||
        border-left: 10px solid #ddd; } }
 | 
			
		||||
  /* line 112, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .l-infobubble-wrapper.arw-top .l-infobubble::before {
 | 
			
		||||
    top: 20px; }
 | 
			
		||||
  /* line 101, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 118, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .l-infobubble-wrapper.arw-btm .l-infobubble::before {
 | 
			
		||||
    bottom: 20px; }
 | 
			
		||||
  /* line 106, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 123, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .l-infobubble-wrapper.arw-down {
 | 
			
		||||
    margin-bottom: 10px; }
 | 
			
		||||
    /* line 108, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
    /* line 125, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
    .l-infobubble-wrapper.arw-down .l-infobubble::before {
 | 
			
		||||
      left: 50%;
 | 
			
		||||
      top: 100%;
 | 
			
		||||
@@ -4477,21 +4807,21 @@ input[type="text"] {
 | 
			
		||||
      border-left: 5px solid transparent;
 | 
			
		||||
      border-right: 5px solid transparent;
 | 
			
		||||
      border-top: 7.5px solid #ddd; }
 | 
			
		||||
  /* line 117, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 134, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .l-infobubble-wrapper .arw {
 | 
			
		||||
    z-index: 2; }
 | 
			
		||||
  /* line 120, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 137, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .l-infobubble-wrapper.arw-up .arw.arw-down, .l-infobubble-wrapper.arw-down .arw.arw-up {
 | 
			
		||||
    display: none; }
 | 
			
		||||
 | 
			
		||||
/* line 127, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
/* line 144, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
.l-thumbsbubble-wrapper .arw-up {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  border-left: 6.66667px solid transparent;
 | 
			
		||||
  border-right: 6.66667px solid transparent;
 | 
			
		||||
  border-bottom: 10px solid #4d4d4d; }
 | 
			
		||||
/* line 130, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
/* line 147, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
.l-thumbsbubble-wrapper .arw-down {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
@@ -4499,7 +4829,7 @@ input[type="text"] {
 | 
			
		||||
  border-right: 6.66667px solid transparent;
 | 
			
		||||
  border-top: 10px solid #4d4d4d; }
 | 
			
		||||
 | 
			
		||||
/* line 134, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
/* line 151, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
.s-infobubble {
 | 
			
		||||
  -moz-border-radius: 2px;
 | 
			
		||||
  -webkit-border-radius: 2px;
 | 
			
		||||
@@ -4510,22 +4840,22 @@ input[type="text"] {
 | 
			
		||||
  background: #ddd;
 | 
			
		||||
  color: #666;
 | 
			
		||||
  font-size: 0.8rem; }
 | 
			
		||||
  /* line 141, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 158, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .s-infobubble .title {
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    font-weight: bold; }
 | 
			
		||||
  /* line 146, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 163, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .s-infobubble tr td {
 | 
			
		||||
    border-top: 1px solid #c4c4c4;
 | 
			
		||||
    font-size: 0.9em; }
 | 
			
		||||
  /* line 150, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 167, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .s-infobubble tr:first-child td {
 | 
			
		||||
    border-top: none; }
 | 
			
		||||
  /* line 154, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  /* line 171, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
  .s-infobubble .value {
 | 
			
		||||
    color: #333333; }
 | 
			
		||||
 | 
			
		||||
/* line 159, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
/* line 176, ../sass/helpers/_bubbles.scss */
 | 
			
		||||
.s-thumbsbubble {
 | 
			
		||||
  background: #4d4d4d;
 | 
			
		||||
  color: #b3b3b3; }
 | 
			
		||||
@@ -4580,7 +4910,7 @@ input[type="text"] {
 | 
			
		||||
    right: 0;
 | 
			
		||||
    width: auto;
 | 
			
		||||
    height: 5px; }
 | 
			
		||||
    /* line 186, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 187, ../sass/_mixins.scss */
 | 
			
		||||
    .split-layout.horizontal > .splitter:before {
 | 
			
		||||
      -moz-transition-property: "border-color";
 | 
			
		||||
      -o-transition-property: "border-color";
 | 
			
		||||
@@ -4604,7 +4934,7 @@ input[type="text"] {
 | 
			
		||||
      top: 2px;
 | 
			
		||||
      left: 5px;
 | 
			
		||||
      right: 5px; }
 | 
			
		||||
    /* line 208, ../sass/_mixins.scss */
 | 
			
		||||
    /* line 209, ../sass/_mixins.scss */
 | 
			
		||||
    .split-layout.horizontal > .splitter:not(.disabled):hover:before {
 | 
			
		||||
      -moz-transition-property: "border-color";
 | 
			
		||||
      -o-transition-property: "border-color";
 | 
			
		||||
@@ -4634,7 +4964,7 @@ input[type="text"] {
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  cursor: col-resize;
 | 
			
		||||
  width: 5px; }
 | 
			
		||||
  /* line 186, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 187, ../sass/_mixins.scss */
 | 
			
		||||
  .split-layout.vertical > .splitter:before {
 | 
			
		||||
    -moz-transition-property: "border-color";
 | 
			
		||||
    -o-transition-property: "border-color";
 | 
			
		||||
@@ -4658,7 +4988,7 @@ input[type="text"] {
 | 
			
		||||
    left: 2px;
 | 
			
		||||
    bottom: 5px;
 | 
			
		||||
    top: 5px; }
 | 
			
		||||
  /* line 208, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 209, ../sass/_mixins.scss */
 | 
			
		||||
  .split-layout.vertical > .splitter:not(.disabled):hover:before {
 | 
			
		||||
    -moz-transition-property: "border-color";
 | 
			
		||||
    -o-transition-property: "border-color";
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,33 @@
 | 
			
		||||
/************************** CONTROLS */
 | 
			
		||||
/************************** PATHS */
 | 
			
		||||
/************************** TIMINGS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
 | 
			
		||||
/************************** MOBILE TREE MENU DIMENSIONS */
 | 
			
		||||
/************************** WINDOW DIMENSIONS FOR RWD */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -78,6 +105,27 @@
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -103,7 +151,7 @@
 | 
			
		||||
ul.tree {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  padding: 0; }
 | 
			
		||||
  /* line 276, ../sass/_mixins.scss */
 | 
			
		||||
  /* line 277, ../sass/_mixins.scss */
 | 
			
		||||
  ul.tree li {
 | 
			
		||||
    list-style-type: none;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
@@ -133,10 +181,11 @@ ul.tree {
 | 
			
		||||
        margin-left: 5px;
 | 
			
		||||
        font-size: 0.75em;
 | 
			
		||||
        width: 10px; }
 | 
			
		||||
        /* line 45, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item .view-control:hover {
 | 
			
		||||
          color: #ffc700; }
 | 
			
		||||
      /* line 50, ../sass/tree/_tree.scss */
 | 
			
		||||
        @media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
          /* line 47, ../sass/tree/_tree.scss */
 | 
			
		||||
          ul.tree li span.tree-item .view-control:hover {
 | 
			
		||||
            color: #ffc700; } }
 | 
			
		||||
      /* line 53, ../sass/tree/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item .label {
 | 
			
		||||
        display: block;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
@@ -148,7 +197,7 @@ ul.tree {
 | 
			
		||||
        width: auto;
 | 
			
		||||
        height: auto;
 | 
			
		||||
        left: 15px; }
 | 
			
		||||
        /* line 57, ../sass/tree/_tree.scss */
 | 
			
		||||
        /* line 60, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item .label .type-icon {
 | 
			
		||||
          overflow: false;
 | 
			
		||||
          position: absolute;
 | 
			
		||||
@@ -163,12 +212,12 @@ ul.tree {
 | 
			
		||||
          left: 5px;
 | 
			
		||||
          right: auto;
 | 
			
		||||
          width: 1em; }
 | 
			
		||||
          /* line 65, ../sass/tree/_tree.scss */
 | 
			
		||||
          /* line 68, ../sass/tree/_tree.scss */
 | 
			
		||||
          ul.tree li span.tree-item .label .type-icon .icon.l-icon-link, ul.tree li span.tree-item .label .type-icon .icon.l-icon-alert {
 | 
			
		||||
            text-shadow: black 0 1px 2px;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            z-index: 2; }
 | 
			
		||||
          /* line 71, ../sass/tree/_tree.scss */
 | 
			
		||||
          /* line 74, ../sass/tree/_tree.scss */
 | 
			
		||||
          ul.tree li span.tree-item .label .type-icon .icon.l-icon-alert {
 | 
			
		||||
            color: #ff3c00;
 | 
			
		||||
            font-size: 8px;
 | 
			
		||||
@@ -177,7 +226,7 @@ ul.tree {
 | 
			
		||||
            width: 8px;
 | 
			
		||||
            top: 1px;
 | 
			
		||||
            right: -2px; }
 | 
			
		||||
          /* line 77, ../sass/tree/_tree.scss */
 | 
			
		||||
          /* line 80, ../sass/tree/_tree.scss */
 | 
			
		||||
          ul.tree li span.tree-item .label .type-icon .icon.l-icon-link {
 | 
			
		||||
            color: #49dedb;
 | 
			
		||||
            font-size: 8px;
 | 
			
		||||
@@ -186,7 +235,7 @@ ul.tree {
 | 
			
		||||
            width: 8px;
 | 
			
		||||
            left: -3px;
 | 
			
		||||
            bottom: 5px; }
 | 
			
		||||
        /* line 86, ../sass/tree/_tree.scss */
 | 
			
		||||
        /* line 89, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item .label .title-label {
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          position: absolute;
 | 
			
		||||
@@ -201,51 +250,110 @@ ul.tree {
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          text-overflow: ellipsis;
 | 
			
		||||
          white-space: nowrap; }
 | 
			
		||||
      /* line 97, ../sass/tree/_tree.scss */
 | 
			
		||||
      /* line 100, ../sass/tree/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item.loading {
 | 
			
		||||
        pointer-events: none; }
 | 
			
		||||
        /* line 99, ../sass/tree/_tree.scss */
 | 
			
		||||
        /* line 102, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item.loading .label {
 | 
			
		||||
          opacity: 0.5; }
 | 
			
		||||
          /* line 101, ../sass/tree/_tree.scss */
 | 
			
		||||
          /* line 104, ../sass/tree/_tree.scss */
 | 
			
		||||
          ul.tree li span.tree-item.loading .label .title-label {
 | 
			
		||||
            font-style: italic; }
 | 
			
		||||
        /* line 105, ../sass/tree/_tree.scss */
 | 
			
		||||
        /* line 108, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item.loading .wait-spinner {
 | 
			
		||||
          margin-left: 14px; }
 | 
			
		||||
      /* line 110, ../sass/tree/_tree.scss */
 | 
			
		||||
      /* line 113, ../sass/tree/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item.selected {
 | 
			
		||||
        background: #005177;
 | 
			
		||||
        color: #fff; }
 | 
			
		||||
        /* line 114, ../sass/tree/_tree.scss */
 | 
			
		||||
        /* line 117, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item.selected .view-control {
 | 
			
		||||
          color: #0099cc; }
 | 
			
		||||
        /* line 117, ../sass/tree/_tree.scss */
 | 
			
		||||
        /* line 120, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item.selected .label .type-icon {
 | 
			
		||||
          color: #fff; }
 | 
			
		||||
      /* line 123, ../sass/tree/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item:not(.selected):hover {
 | 
			
		||||
        background: #404040;
 | 
			
		||||
        color: #cccccc; }
 | 
			
		||||
        /* line 126, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item:not(.selected):hover .context-trigger {
 | 
			
		||||
          display: block; }
 | 
			
		||||
        /* line 129, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item:not(.selected):hover .icon {
 | 
			
		||||
          color: #33ccff; }
 | 
			
		||||
      /* line 135, ../sass/tree/_tree.scss */
 | 
			
		||||
      @media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
 | 
			
		||||
        /* line 128, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item:not(.selected):hover {
 | 
			
		||||
          background: #404040;
 | 
			
		||||
          color: #cccccc; }
 | 
			
		||||
          /* line 131, ../sass/tree/_tree.scss */
 | 
			
		||||
          ul.tree li span.tree-item:not(.selected):hover .context-trigger {
 | 
			
		||||
            display: block; }
 | 
			
		||||
          /* line 134, ../sass/tree/_tree.scss */
 | 
			
		||||
          ul.tree li span.tree-item:not(.selected):hover .icon {
 | 
			
		||||
            color: #33ccff; } }
 | 
			
		||||
      /* line 141, ../sass/tree/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item:not(.loading) {
 | 
			
		||||
        cursor: pointer; }
 | 
			
		||||
      /* line 139, ../sass/tree/_tree.scss */
 | 
			
		||||
      /* line 145, ../sass/tree/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item .context-trigger {
 | 
			
		||||
        top: -1px;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        right: 3px; }
 | 
			
		||||
        /* line 145, ../sass/tree/_tree.scss */
 | 
			
		||||
        /* line 151, ../sass/tree/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item .context-trigger .invoke-menu {
 | 
			
		||||
          font-size: 0.75em;
 | 
			
		||||
          height: 0.9rem;
 | 
			
		||||
          line-height: 0.9rem; }
 | 
			
		||||
  /* line 154, ../sass/tree/_tree.scss */
 | 
			
		||||
  /* line 160, ../sass/tree/_tree.scss */
 | 
			
		||||
  ul.tree ul.tree {
 | 
			
		||||
    margin-left: 15px; }
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
 | 
			
		||||
  /* line 24, ../sass/mobile/_tree.scss */
 | 
			
		||||
  ul.tree {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0; }
 | 
			
		||||
    /* line 277, ../sass/_mixins.scss */
 | 
			
		||||
    ul.tree li {
 | 
			
		||||
      list-style-type: none;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      padding: 0; }
 | 
			
		||||
    /* line 29, ../sass/mobile/_tree.scss */
 | 
			
		||||
    ul.tree li span.tree-item {
 | 
			
		||||
      height: 38px;
 | 
			
		||||
      line-height: 38px;
 | 
			
		||||
      padding-top: 3px;
 | 
			
		||||
      padding-bottom: 3px;
 | 
			
		||||
      margin-bottom: 0px; }
 | 
			
		||||
      /* line 36, ../sass/mobile/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item .view-control {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        right: 13px;
 | 
			
		||||
        font-size: 1.8em;
 | 
			
		||||
        right: 0px;
 | 
			
		||||
        width: 35px;
 | 
			
		||||
        text-align: center; }
 | 
			
		||||
      /* line 45, ../sass/mobile/_tree.scss */
 | 
			
		||||
      ul.tree li span.tree-item .label {
 | 
			
		||||
        left: 3px;
 | 
			
		||||
        right: 45px;
 | 
			
		||||
        font-size: 1.2em; }
 | 
			
		||||
        /* line 54, ../sass/mobile/_tree.scss */
 | 
			
		||||
        ul.tree li span.tree-item .label .title-label {
 | 
			
		||||
          right: 16.9px; }
 | 
			
		||||
    /* line 63, ../sass/mobile/_tree.scss */
 | 
			
		||||
    ul.tree ul.tree {
 | 
			
		||||
      margin-left: 7px; } }
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,14 @@
 | 
			
		||||
@import "compass/utilities";
 | 
			
		||||
 | 
			
		||||
@import "mixins";
 | 
			
		||||
@import "mobile/mixins";
 | 
			
		||||
 | 
			
		||||
@import "effects";
 | 
			
		||||
@import "global";
 | 
			
		||||
@import "fonts";
 | 
			
		||||
@import "user-environ/layout";
 | 
			
		||||
@import "mobile/layout";
 | 
			
		||||
 | 
			
		||||
@import "fixed-position";
 | 
			
		||||
@import "about";
 | 
			
		||||
@import "text";
 | 
			
		||||
@@ -45,6 +49,7 @@
 | 
			
		||||
@import "controls/controls";
 | 
			
		||||
@import "controls/lists";
 | 
			
		||||
@import "controls/menus";
 | 
			
		||||
@import "mobile/controls/menus";
 | 
			
		||||
@import "controls/time-controller";
 | 
			
		||||
@import "edit/editor";
 | 
			
		||||
@import "features/imagery";
 | 
			
		||||
@@ -59,6 +64,7 @@
 | 
			
		||||
@import "forms/filter";
 | 
			
		||||
@import "plots/plots-main";
 | 
			
		||||
@import "overlay/overlay";
 | 
			
		||||
@import "mobile/overlay/overlay";
 | 
			
		||||
@import "user-environ/frame";
 | 
			
		||||
@import "user-environ/top-bar";
 | 
			
		||||
@import "user-environ/bottom-bar";
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@mixin absPosDefault($offset: 0px, $overflowHidden: hidden) {
 | 
			
		||||
    overflow: $overflowHidden;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,10 @@
 | 
			
		||||
@import "compass/utilities";
 | 
			
		||||
 | 
			
		||||
@import "constants";
 | 
			
		||||
@import "mobile/constants";
 | 
			
		||||
@import "mixins";
 | 
			
		||||
@import "forms/mixins";
 | 
			
		||||
@import "mobile/mixins";
 | 
			
		||||
@import "forms/elems";
 | 
			
		||||
@import "forms/textarea";
 | 
			
		||||
@import "forms/text-input";
 | 
			
		||||
 
 | 
			
		||||
@@ -79,15 +79,32 @@
 | 
			
		||||
		margin-left: $bubbleArwSize*2;
 | 
			
		||||
		.l-infobubble::before {
 | 
			
		||||
			right: 100%;
 | 
			
		||||
			@include triangle('left', $bubbleArwSize, 1.5, $colorInfoBubbleBg);
 | 
			
		||||
            // NOTE: [MOBILE] REMOVES TRIANGLE
 | 
			
		||||
            // Removes the triangle located on the info
 | 
			
		||||
            // bubble for phones only, for tablets and
 | 
			
		||||
            // desktops, triangle remains.
 | 
			
		||||
            @include desktopandtablet {
 | 
			
		||||
                @include triangle('left', $bubbleArwSize, 1.5, $colorInfoBubbleBg);
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	&.arw-right {
 | 
			
		||||
		margin-right: $bubbleArwSize*2;
 | 
			
		||||
        // NOTE: [MOBILE] REMOVES RIGHT MARGIN
 | 
			
		||||
        // Removes right margin made for the 
 | 
			
		||||
        // triangle on mobile
 | 
			
		||||
        @include desktopandtablet {
 | 
			
		||||
		  margin-right: $bubbleArwSize*2;
 | 
			
		||||
        }
 | 
			
		||||
		.l-infobubble::before {
 | 
			
		||||
			left: 100%;
 | 
			
		||||
			@include triangle('right', $bubbleArwSize, 1.5, $colorInfoBubbleBg);
 | 
			
		||||
            // NOTE: [MOBILE] REMOVES TRIANGLE
 | 
			
		||||
            // Removes the triangle located on the info
 | 
			
		||||
            // bubble for phones only, for tablets and
 | 
			
		||||
            // desktops, triangle remains.
 | 
			
		||||
            @include desktopandtablet {
 | 
			
		||||
                @include triangle('right', $bubbleArwSize, 1.5, $colorInfoBubbleBg);
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -124,12 +141,12 @@
 | 
			
		||||
//************************************************* LOOK AND FEEL
 | 
			
		||||
 | 
			
		||||
.l-thumbsbubble-wrapper {
 | 
			
		||||
	.arw-up {
 | 
			
		||||
		@include triangle('up', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
 | 
			
		||||
	}
 | 
			
		||||
	.arw-down {
 | 
			
		||||
		@include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
 | 
			
		||||
	}
 | 
			
		||||
    .arw-up {
 | 
			
		||||
        @include triangle('up', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
 | 
			
		||||
    }
 | 
			
		||||
    .arw-down {
 | 
			
		||||
        @include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
.s-infobubble {
 | 
			
		||||
	$emFg: darken($colorInfoBubbleFg, 20%);
 | 
			
		||||
 
 | 
			
		||||
@@ -26,5 +26,8 @@
 | 
			
		||||
@import "compass/utilities";
 | 
			
		||||
 | 
			
		||||
@import "constants";
 | 
			
		||||
@import "mobile/constants";
 | 
			
		||||
@import "mixins";
 | 
			
		||||
@import "items/item";
 | 
			
		||||
@import "mobile/mixins";
 | 
			
		||||
@import "items/item";
 | 
			
		||||
@import "mobile/item";
 | 
			
		||||
							
								
								
									
										87
									
								
								platform/commonUI/general/res/sass/mobile/_constants.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								platform/commonUI/general/res/sass/mobile/_constants.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
 | 
			
		||||
$mobile-listIcon: 30px;
 | 
			
		||||
$mobile-listRight: 10px;
 | 
			
		||||
 | 
			
		||||
$phone-itemHeight: $ueBrowseGridItemLg/4;
 | 
			
		||||
$tablet-itemHeight: $ueBrowseGridItemLg/3;
 | 
			
		||||
 | 
			
		||||
/************************** MOBILE TREE MENU DIMENSIONS */
 | 
			
		||||
$mobile-treeHeight: 38px;
 | 
			
		||||
$mobile-startingTreeLeft: 3px;
 | 
			
		||||
$mobile-runningTreeLeft: 7px;
 | 
			
		||||
$mobile-treeRight: 13px;
 | 
			
		||||
 | 
			
		||||
/************************** WINDOW DIMENSIONS FOR RWD */
 | 
			
		||||
$phoMaxW: 514px;
 | 
			
		||||
$phoMaxH: 740px;
 | 
			
		||||
 | 
			
		||||
$tabMinW: 515px;
 | 
			
		||||
$tabMaxW: 799px;
 | 
			
		||||
 | 
			
		||||
$tabMinH: 741px;
 | 
			
		||||
$tabMaxH: 1024px;
 | 
			
		||||
 | 
			
		||||
$compMinW: 800px;
 | 
			
		||||
$compMinH: 1025px;
 | 
			
		||||
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
$screenPortrait: "screen and (orientation: portrait)";
 | 
			
		||||
$screenLandscape: "screen and (orientation: landscape)";
 | 
			
		||||
 | 
			
		||||
$mobileDevice: "(max-device-width: #{$tabMaxW}) and (max-device-height: #{$tabMaxH})";
 | 
			
		||||
$mobileDeviceEmu: "(max-device-width: #{$tabMaxH}) and (max-device-height: #{$tabMaxW})";
 | 
			
		||||
 | 
			
		||||
$phonePortraitCheck: "(max-width: #{$phoMaxW}) and (max-height: #{$phoMaxH})";
 | 
			
		||||
$phoneLandscapeCheck: "(max-height: #{$phoMaxW}) and (max-width: #{$phoMaxH})";
 | 
			
		||||
 | 
			
		||||
$tabWidPorCheck: "(min-width: #{$tabMinW}) and (max-width: #{$tabMaxW})";
 | 
			
		||||
$tabHeiPorCheck: "(min-height: #{$tabMinH}) and (max-height: #{$tabMaxH})";
 | 
			
		||||
$tabletPortraitCheck: "#{$tabWidPorCheck} and #{$tabHeiPorCheck}";
 | 
			
		||||
 | 
			
		||||
$tabWidLanCheck: "(min-height: #{$tabMinW}) and (max-height: #{$tabMaxW})";
 | 
			
		||||
$tabHeiLanCheck: "(min-width: #{$tabMinH}) and (max-width: #{$tabMaxH})";
 | 
			
		||||
$tabletLandscapeCheck: "#{$tabWidLanCheck} and #{$tabHeiLanCheck}";
 | 
			
		||||
 | 
			
		||||
$desktopPortraitCheck: "(min-device-width: #{$compMinW}) and (min-device-height: #{$compMinH})";
 | 
			
		||||
$desktopLandscapeCheck: "(min-device-width: #{$compMinH}) and (min-device-height: #{$compMinW})";
 | 
			
		||||
 | 
			
		||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
 | 
			
		||||
$phonePortrait: "#{$screenPortrait} and #{$phonePortraitCheck} and #{$mobileDevice}";
 | 
			
		||||
$phoneLandscape: "#{$screenLandscape} and #{$phoneLandscapeCheck} and #{$mobileDevice}";
 | 
			
		||||
$phoneLandscapeEmu: "#{$screenLandscape} and #{$phoneLandscapeCheck} and #{$mobileDeviceEmu}";
 | 
			
		||||
 | 
			
		||||
$tabletPortrait: "#{$screenPortrait} and #{$tabletPortraitCheck} and #{$mobileDevice}";
 | 
			
		||||
$tabletLandscape: "#{$screenLandscape} and #{$tabletLandscapeCheck} and #{$mobileDevice}";
 | 
			
		||||
$tabletLandscapeEmu: "#{$screenLandscape} and #{$tabletLandscapeCheck} and #{$mobileDeviceEmu}";
 | 
			
		||||
 | 
			
		||||
$desktopPortrait: "screen and #{$desktopPortraitCheck}";
 | 
			
		||||
$desktopLandscape: "screen and #{$desktopLandscapeCheck}";
 | 
			
		||||
 | 
			
		||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
 | 
			
		||||
$phoneRepSizePortrait: 19px;
 | 
			
		||||
$phoneRepSizeLandscape: 66%;
 | 
			
		||||
$tabletRepSizePortrait: 500px;
 | 
			
		||||
$tabletRepSizeLandscape: 78%;
 | 
			
		||||
$desktopMenuSize: 25%;
 | 
			
		||||
							
								
								
									
										130
									
								
								platform/commonUI/general/res/sass/mobile/_item.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								platform/commonUI/general/res/sass/mobile/_item.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
// Sets the size of the items in the folder
 | 
			
		||||
// representation. Instead of a grid,
 | 
			
		||||
// a list is used.
 | 
			
		||||
 | 
			
		||||
.items-holder {
 | 
			
		||||
    .item {
 | 
			
		||||
        &.grid-item {
 | 
			
		||||
            $dWid: $ueBrowseGridItemLg;
 | 
			
		||||
            $dHei: $ueBrowseGridItemLg;
 | 
			
		||||
            @include phoneandtablet {
 | 
			
		||||
                $dWid: 100%;
 | 
			
		||||
                .mobile-grid-nav {
 | 
			
		||||
                    top: 0px;
 | 
			
		||||
                    bottom: 0px;
 | 
			
		||||
                    right: 55px;
 | 
			
		||||
                }
 | 
			
		||||
                .mobile-info {
 | 
			
		||||
                    text-align: center;
 | 
			
		||||
                    width: 50px;
 | 
			
		||||
                    right: 0px;
 | 
			
		||||
                    left: auto;
 | 
			
		||||
                    font-size: 1.3em;
 | 
			
		||||
                }
 | 
			
		||||
                .bar {
 | 
			
		||||
                    &.bottom-bar.abs {
 | 
			
		||||
                        top: 0px;
 | 
			
		||||
                        height: auto;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                }
 | 
			
		||||
                .item-main {
 | 
			
		||||
                    .item-type {
 | 
			
		||||
                        font-size: $mobile-listIcon;
 | 
			
		||||
                        top: 0px;
 | 
			
		||||
                        left: 0px;
 | 
			
		||||
                        text-align: left;
 | 
			
		||||
                        height: auto
 | 
			
		||||
                    }
 | 
			
		||||
                    .item-open {
 | 
			
		||||
                       display: none;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .title, .details {
 | 
			
		||||
                    margin-left: $mobile-listIcon;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @include phone {
 | 
			
		||||
                $dHei: $phone-itemHeight;
 | 
			
		||||
                width: $dWid;
 | 
			
		||||
                height: $dHei;
 | 
			
		||||
                .mobile-right {
 | 
			
		||||
                    top: 100%;
 | 
			
		||||
                }
 | 
			
		||||
                .mobile-info {
 | 
			
		||||
                    line-height: $phone-itemHeight * .5;
 | 
			
		||||
                }
 | 
			
		||||
                .item-main {
 | 
			
		||||
                    .item-type {
 | 
			
		||||
                        line-height: $phone-itemHeight * .8;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .title {
 | 
			
		||||
                    margin-right: $mobile-listRight;
 | 
			
		||||
                    line-height: $phone-itemHeight * .5;
 | 
			
		||||
                }
 | 
			
		||||
                .details {
 | 
			
		||||
                    margin-right: $mobile-listRight;
 | 
			
		||||
                    line-height: 0px;
 | 
			
		||||
                }                
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            @include tablet {
 | 
			
		||||
                $dHei: $tablet-itemHeight;
 | 
			
		||||
                width: $dWid;
 | 
			
		||||
                height: $dHei;
 | 
			
		||||
                .mobile-right {
 | 
			
		||||
                    top: 100%;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                .mobile-info {
 | 
			
		||||
                    line-height: $tablet-itemHeight * .57;
 | 
			
		||||
                }
 | 
			
		||||
                .item-main {
 | 
			
		||||
                    .item-type {
 | 
			
		||||
                        font-size: $mobile-listIcon;
 | 
			
		||||
                        line-height: $tablet-itemHeight * .75;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .title {
 | 
			
		||||
                    margin-right: $mobile-listRight;
 | 
			
		||||
                    line-height: $tablet-itemHeight * .57;
 | 
			
		||||
                }
 | 
			
		||||
                .details {
 | 
			
		||||
                    margin-right: $mobile-listRight;
 | 
			
		||||
                    line-height: 0px;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            @include desktop {
 | 
			
		||||
                $dWid: $ueBrowseGridItemLg;
 | 
			
		||||
                $dHei: $ueBrowseGridItemLg;
 | 
			
		||||
                width: $dWid;
 | 
			
		||||
                height: $dHei; 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										218
									
								
								platform/commonUI/general/res/sass/mobile/_layout.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								platform/commonUI/general/res/sass/mobile/_layout.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,218 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
// Wrapper of the entire 2 panes, only enacted on
 | 
			
		||||
// phone and tablet. Also for the panes
 | 
			
		||||
 | 
			
		||||
.browse-wrapper,
 | 
			
		||||
.mobile-pane {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        left: 0; top: 0;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Default views of the panels
 | 
			
		||||
// if in desktop browser
 | 
			
		||||
.desktop-browse {
 | 
			
		||||
    @include desktop {
 | 
			
		||||
        min-width: 150px;
 | 
			
		||||
        max-width: 800px;
 | 
			
		||||
        width: $desktopMenuSize;   
 | 
			
		||||
    }   
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When the tree is hidden, these are the
 | 
			
		||||
// classes used for the left menu and the
 | 
			
		||||
// right representation.
 | 
			
		||||
.browse-hidetree {
 | 
			
		||||
    // NOTE: DISABLED SELECTION
 | 
			
		||||
    // Selection disabled in both panes
 | 
			
		||||
    // causing cut/copy/paste menu to
 | 
			
		||||
    // not appear. Should me moved in
 | 
			
		||||
    // future to properly work
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        @include user-select(none);
 | 
			
		||||
    }
 | 
			
		||||
    // Sets the left tree menu when the tree
 | 
			
		||||
    // is hidden. 
 | 
			
		||||
    .mobile-pane.left-menu {
 | 
			
		||||
        @include phoneandtablet {
 | 
			
		||||
            @include trans-prop-nice(opacity, .4s);
 | 
			
		||||
            opacity: 0;
 | 
			
		||||
            right: 100% !important;
 | 
			
		||||
            width: auto !important;
 | 
			
		||||
            overflow-y: hidden;
 | 
			
		||||
            overflow-x: hidden;       
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Sets the right represenation when
 | 
			
		||||
    // the tree is hidden. 
 | 
			
		||||
    .mobile-pane.right-repr {       
 | 
			
		||||
        @include phoneandtablet {         
 | 
			
		||||
            @include slMenuTransitions;
 | 
			
		||||
            left: auto !important;
 | 
			
		||||
            width: 100% !important;
 | 
			
		||||
        }
 | 
			
		||||
    }    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mobile-tree-holder {
 | 
			
		||||
    top: 30px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When the tree is shown, these are
 | 
			
		||||
// the classes used for the left menu
 | 
			
		||||
// and the right menu (for each device &
 | 
			
		||||
// orientation combination, separate 
 | 
			
		||||
// parameters are used)
 | 
			
		||||
.browse-showtree {
 | 
			
		||||
    // NOTE: DISABLED SELECTION
 | 
			
		||||
    // Selection disabled in both panes
 | 
			
		||||
    // causing cut/copy/paste menu to
 | 
			
		||||
    // not appear. Should me moved in
 | 
			
		||||
    // future to properly work
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        @include user-select(none);
 | 
			
		||||
    }
 | 
			
		||||
    // Sets the left tree menu when the tree
 | 
			
		||||
    // is shown.     
 | 
			
		||||
    .mobile-pane.left-menu {
 | 
			
		||||
        @include phoneandtablet {
 | 
			
		||||
            @include trans-prop-nice(opacity, .4s);
 | 
			
		||||
            opacity: 1;
 | 
			
		||||
            display: block !important;
 | 
			
		||||
            width: auto !important;
 | 
			
		||||
        }
 | 
			
		||||
        // On both phones and tablets, the amount of
 | 
			
		||||
        // space allowed for the right pane is specified
 | 
			
		||||
        @include phonePortrait {
 | 
			
		||||
            right: $phoneRepSizePortrait !important;
 | 
			
		||||
        }
 | 
			
		||||
        @include phoneLandscape {
 | 
			
		||||
            right: $phoneRepSizeLandscape !important;
 | 
			
		||||
        }
 | 
			
		||||
        @include tabletPortrait {
 | 
			
		||||
            right: $tabletRepSizePortrait !important;
 | 
			
		||||
        }
 | 
			
		||||
        @include tabletLandscape {
 | 
			
		||||
            right: $tabletRepSizeLandscape !important;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Sets the right represenation when
 | 
			
		||||
    // the tree is shown.     
 | 
			
		||||
    .mobile-pane.right-repr {
 | 
			
		||||
        @include phoneandtablet {
 | 
			
		||||
            @include slMenuTransitions;
 | 
			
		||||
            left: auto !important;
 | 
			
		||||
        }
 | 
			
		||||
        // On both phones and tablets, the width of
 | 
			
		||||
        // the right pane is specified
 | 
			
		||||
        @include phonePortrait {
 | 
			
		||||
            width: $phoneRepSizePortrait !important;
 | 
			
		||||
        }
 | 
			
		||||
        @include phoneLandscape {
 | 
			
		||||
            width: $phoneRepSizeLandscape !important;
 | 
			
		||||
        }
 | 
			
		||||
        @include tabletPortrait {
 | 
			
		||||
            width: $tabletRepSizePortrait !important;
 | 
			
		||||
        }
 | 
			
		||||
        @include tabletLandscape {
 | 
			
		||||
            width: $tabletRepSizeLandscape !important;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Button position is set as absolute with transitions
 | 
			
		||||
.button-pos {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Object header must be moved
 | 
			
		||||
// over to make space for the 
 | 
			
		||||
// hamburger icon
 | 
			
		||||
.object-header {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        position: relative;
 | 
			
		||||
        left: 44px;        
 | 
			
		||||
        .label {
 | 
			
		||||
            .context-available {
 | 
			
		||||
                opacity: 1 !important;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.desktop-hide {
 | 
			
		||||
    @include desktop {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hides objects on phone and tablet
 | 
			
		||||
.mobile-hide {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mobile-important-hide {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        display: none !important;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mobile-back-hide {
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
        @include trans-prop-nice(opacity, .4s);
 | 
			
		||||
        opacity: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hides objects on phone and tablet
 | 
			
		||||
.mobile-back-unhide {
 | 
			
		||||
        pointer-events: all;
 | 
			
		||||
        @include trans-prop-nice(opacity, .4s);
 | 
			
		||||
        opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hides objects only on the phone
 | 
			
		||||
.phone-hide {
 | 
			
		||||
    @include phone {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tree-holder {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        overflow-x: hidden !important;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
.mobile-disable-select {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        @include user-select(none);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										107
									
								
								platform/commonUI/general/res/sass/mobile/_mixins.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								platform/commonUI/general/res/sass/mobile/_mixins.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
// Phones in any orientation
 | 
			
		||||
@mixin phone {
 | 
			
		||||
    @media #{$phonePortrait},
 | 
			
		||||
           #{$phoneLandscape},
 | 
			
		||||
           #{$phoneLandscapeEmu} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Phones in portrait orientation
 | 
			
		||||
@mixin phonePortrait {
 | 
			
		||||
    @media #{$phonePortrait} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Phones in landscape orientation
 | 
			
		||||
@mixin phoneLandscape {
 | 
			
		||||
    @media #{$phoneLandscape},
 | 
			
		||||
           #{$phoneLandscapeEmu} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tablets in any orientation
 | 
			
		||||
@mixin tablet {
 | 
			
		||||
    @media #{$tabletPortrait},
 | 
			
		||||
           #{$tabletLandscape},
 | 
			
		||||
           #{$tabletLandscapeEmu} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tablets in portrait orientation
 | 
			
		||||
@mixin tabletPortrait {
 | 
			
		||||
    @media #{$tabletPortrait} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tablets in landscape orientation
 | 
			
		||||
@mixin tabletLandscape {
 | 
			
		||||
    @media #{$tabletLandscape},
 | 
			
		||||
           #{$tabletLandscapeEmu} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Phones and tablets in any orientation
 | 
			
		||||
@mixin phoneandtablet {
 | 
			
		||||
    @media #{$phonePortrait},
 | 
			
		||||
           #{$phoneLandscape},
 | 
			
		||||
           #{$phoneLandscapeEmu},
 | 
			
		||||
           #{$tabletPortrait},
 | 
			
		||||
           #{$tabletLandscape},
 | 
			
		||||
           #{$tabletLandscapeEmu} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Desktop monitors in any orientation
 | 
			
		||||
@mixin desktopandtablet {
 | 
			
		||||
    @media #{$tabletPortrait},
 | 
			
		||||
           #{$tabletLandscape},
 | 
			
		||||
           #{$tabletLandscapeEmu},
 | 
			
		||||
           #{$desktopPortrait},
 | 
			
		||||
           #{$desktopLandscape} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Desktop monitors in any orientation
 | 
			
		||||
@mixin desktop {
 | 
			
		||||
    @media #{$desktopPortrait},
 | 
			
		||||
           #{$desktopLandscape} {
 | 
			
		||||
        @content
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Transition used for the slide menu
 | 
			
		||||
@mixin slMenuTransitions {
 | 
			
		||||
    @include transition-duration(.35s);
 | 
			
		||||
    transition-timing-function: ease;
 | 
			
		||||
    backface-visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								platform/commonUI/general/res/sass/mobile/_tree.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								platform/commonUI/general/res/sass/mobile/_tree.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ul.tree {
 | 
			
		||||
    // Only applies to phones and tablets
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        @include menuUlReset();
 | 
			
		||||
        li {
 | 
			
		||||
            span.tree-item {
 | 
			
		||||
                // Adds some space to the top of each tree item
 | 
			
		||||
                height: $mobile-treeHeight;
 | 
			
		||||
                line-height: $mobile-treeHeight;
 | 
			
		||||
                padding-top: $interiorMarginSm;
 | 
			
		||||
                padding-bottom: $interiorMarginSm;
 | 
			
		||||
                margin-bottom: 0px;
 | 
			
		||||
                .view-control {
 | 
			
		||||
                    position: absolute;
 | 
			
		||||
                    right: $mobile-treeRight;
 | 
			
		||||
                    font-size: 1.8em;
 | 
			
		||||
                    right: 0px;
 | 
			
		||||
                    width: 35px;
 | 
			
		||||
                    text-align: center;
 | 
			
		||||
                }                   
 | 
			
		||||
 | 
			
		||||
                .label {
 | 
			
		||||
                    // Designates the starting left margin
 | 
			
		||||
                    // (indentation) of 'My Items'
 | 
			
		||||
                    // Also adds right space for selection button
 | 
			
		||||
                    left: $mobile-startingTreeLeft;
 | 
			
		||||
                    right: 45px;
 | 
			
		||||
                    font-size: 1.2em;
 | 
			
		||||
                    // Allows tree item name to stop prior
 | 
			
		||||
                    // to the arrow
 | 
			
		||||
                    .title-label {
 | 
			
		||||
                        right: $mobile-treeRight * 1.3;
 | 
			
		||||
                    }
 | 
			
		||||
                }             
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Sets the margin on the left, which causes the
 | 
			
		||||
        // running indentation after each folder is made
 | 
			
		||||
        ul.tree {
 | 
			
		||||
            margin-left: $mobile-runningTreeLeft;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
// Mobile hamburger icon is
 | 
			
		||||
// sized according to the device
 | 
			
		||||
.mobile-menu-icon {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        font-size: 21px;
 | 
			
		||||
        padding-top: $imageThumbPad;
 | 
			
		||||
    }
 | 
			
		||||
    @include desktop {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }       
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
.overlay {
 | 
			
		||||
    @include phoneandtablet {
 | 
			
		||||
        $m: 0;
 | 
			
		||||
        // Removes curved edges on the dialog box
 | 
			
		||||
        // and makes it take up fullscreen
 | 
			
		||||
        >.holder {
 | 
			
		||||
          @include border-radius($m);
 | 
			
		||||
          top: $m; right: $m; bottom: $m; left: $m;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,5 +20,6 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
@import "constants";
 | 
			
		||||
@import "mobile/constants";
 | 
			
		||||
@import "themes/theme-espresso";
 | 
			
		||||
@import "main";
 | 
			
		||||
@@ -26,5 +26,8 @@
 | 
			
		||||
@import "compass/utilities";
 | 
			
		||||
 | 
			
		||||
@import "constants";
 | 
			
		||||
@import "mobile/constants";
 | 
			
		||||
@import "mixins";
 | 
			
		||||
@import "tree/tree";
 | 
			
		||||
@import "mobile/mixins";
 | 
			
		||||
@import "tree/tree";
 | 
			
		||||
@import "mobile/tree";
 | 
			
		||||
@@ -42,9 +42,12 @@ ul.tree {
 | 
			
		||||
				font-size: 0.75em;
 | 
			
		||||
				width: $treeVCW;
 | 
			
		||||
				$runningItemW: $interiorMargin + $treeVCW;
 | 
			
		||||
				&:hover {
 | 
			
		||||
					color: $colorItemTreeVCHover;
 | 
			
		||||
				}
 | 
			
		||||
                // NOTE: [Mobile] Removed Hover on Mobile
 | 
			
		||||
                @include desktop {
 | 
			
		||||
                    &:hover {
 | 
			
		||||
                        color: $colorItemTreeVCHover;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			.label {
 | 
			
		||||
@@ -120,16 +123,19 @@ ul.tree {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			&:not(.selected) {
 | 
			
		||||
				&:hover {
 | 
			
		||||
					background: lighten($colorBodyBg, 5%);
 | 
			
		||||
					color: lighten($colorBodyFg, 20%);
 | 
			
		||||
					.context-trigger {
 | 
			
		||||
						display: block;
 | 
			
		||||
					}
 | 
			
		||||
					.icon {
 | 
			
		||||
						color: $colorItemTreeIconHover;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
                // NOTE: [Mobile] Removed Hover on Mobile
 | 
			
		||||
                @include desktop {
 | 
			
		||||
                    &:hover {
 | 
			
		||||
                        background: lighten($colorBodyBg, 5%);
 | 
			
		||||
                        color: lighten($colorBodyFg, 20%);
 | 
			
		||||
                        .context-trigger {
 | 
			
		||||
                            display: block;
 | 
			
		||||
                        }
 | 
			
		||||
                        .icon {
 | 
			
		||||
                            color: $colorItemTreeIconHover;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			&:not(.loading) {
 | 
			
		||||
 
 | 
			
		||||
@@ -265,6 +265,7 @@
 | 
			
		||||
	&.vertical {
 | 
			
		||||
		// Slides left and right
 | 
			
		||||
		>.pane {
 | 
			
		||||
//            @include test();
 | 
			
		||||
			margin-left: $interiorMargin;
 | 
			
		||||
			>.holder {
 | 
			
		||||
				left: 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div class='abs bottom-bar ue-bottom-bar' ng-controller="BottomBarController as bar">
 | 
			
		||||
<div class='abs bottom-bar ue-bottom-bar mobile-disable-select' ng-controller="BottomBarController as bar">
 | 
			
		||||
    <div id='status' class='status-holder'>
 | 
			
		||||
        <mct-include ng-repeat="indicator in bar.getIndicators()"
 | 
			
		||||
                     ng-model="indicator.ngModel"
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div class="menu-element context-menu-wrapper" ng-controller="ContextMenuController">
 | 
			
		||||
<div class="menu-element context-menu-wrapper mobile-disable-select" ng-controller="ContextMenuController">
 | 
			
		||||
    <div class="menu context-menu dropdown">
 | 
			
		||||
        <ul>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,20 +25,24 @@
 | 
			
		||||
	        class="tree-item menus-to-left"
 | 
			
		||||
	        ng-class="{selected: treeNode.isSelected()}"
 | 
			
		||||
	        >
 | 
			
		||||
            <span
 | 
			
		||||
	            class='ui-symbol view-control'
 | 
			
		||||
				ng-click="toggle.toggle(); treeNode.trackExpansion()"
 | 
			
		||||
				ng-if="model.composition !== undefined"
 | 
			
		||||
				>
 | 
			
		||||
                {{toggle.isActive() ? "v" : ">"}}
 | 
			
		||||
            </span>
 | 
			
		||||
            <mct-representation
 | 
			
		||||
				key="'label'"
 | 
			
		||||
            <mct-representation                                
 | 
			
		||||
                key="'label'"
 | 
			
		||||
				mct-object="domainObject"
 | 
			
		||||
				ng-model="ngModel"
 | 
			
		||||
				ng-click="ngModel.selectedObject = domainObject"
 | 
			
		||||
				ng-click="!treeNode.checkMobile() ? ngModel.selectedObject = domainObject :
 | 
			
		||||
                          toggle.toggle(); treeNode.trackExpansion()"
 | 
			
		||||
				>
 | 
			
		||||
            </mct-representation>
 | 
			
		||||
            <span
 | 
			
		||||
	            class='ui-symbol view-control'
 | 
			
		||||
                mct-object="domainObject"
 | 
			
		||||
                ng-model="ngModel"
 | 
			
		||||
				ng-click="treeNode.checkMobile() ? ngModel.selectedObject = domainObject :
 | 
			
		||||
                          toggle.toggle(); treeNode.trackExpansion()"
 | 
			
		||||
				ng-if="model.composition !== undefined || treeNode.checkMobile()"
 | 
			
		||||
				>
 | 
			
		||||
                {{treeNode.checkMobile() ? "}" : toggle.isActive() ? "v" : ">"}}
 | 
			
		||||
            </span>
 | 
			
		||||
        </span>
 | 
			
		||||
        <span
 | 
			
		||||
			class="tree-item-subtree"
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ define(
 | 
			
		||||
         * expand-to-show-navigated-object behavior.)
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function TreeNodeController($scope, $timeout, $rootScope) {
 | 
			
		||||
        function TreeNodeController($scope, $timeout, agentService) {
 | 
			
		||||
            var selectedObject = ($scope.ngModel || {}).selectedObject,
 | 
			
		||||
                isSelected = false,
 | 
			
		||||
                hasBeenExpanded = false;
 | 
			
		||||
@@ -86,7 +86,11 @@ define(
 | 
			
		||||
                    $timeout(function () { hasBeenExpanded = true; }, 0);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            function checkMobile() {
 | 
			
		||||
                return agentService.isMobile(navigator.userAgent);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Consider the currently-navigated object and update
 | 
			
		||||
            // parameters which support display.
 | 
			
		||||
            function checkSelection() {
 | 
			
		||||
@@ -150,6 +154,9 @@ define(
 | 
			
		||||
                 * lazy loading of the node's subtree.
 | 
			
		||||
                 */
 | 
			
		||||
                trackExpansion: trackExpansion,
 | 
			
		||||
                
 | 
			
		||||
                checkMobile: checkMobile,
 | 
			
		||||
                
 | 
			
		||||
                /**
 | 
			
		||||
                 * Check if this not has ever been expanded.
 | 
			
		||||
                 * @returns true if it has been expanded
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								platform/commonUI/general/src/services/AgentService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								platform/commonUI/general/src/services/AgentService.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define,Promise*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module defining AgentService.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The query service handles calls for browser and userAgent
 | 
			
		||||
         * info using a comparison between the userAgent and key
 | 
			
		||||
         * device names
 | 
			
		||||
         */
 | 
			
		||||
        function AgentService($window) {
 | 
			
		||||
            
 | 
			
		||||
            // Gets the UA name if it is one of the following.
 | 
			
		||||
            // If it is not (a desktop for example) nothing is
 | 
			
		||||
            // returned instead
 | 
			
		||||
            function getDeviceUA(ua) {
 | 
			
		||||
                return ua.match(/iPad|iPhone|Android/i) ?
 | 
			
		||||
                        ua.match(/iPad|iPhone|Android/i) : "";
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Checks if gotten device is mobile,
 | 
			
		||||
            // Mobile is defined as a phone or tablet
 | 
			
		||||
            function isMobile(ua) {
 | 
			
		||||
                if (getDeviceUA(ua)) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Checks if device is phone,
 | 
			
		||||
            // phone is designated as only an
 | 
			
		||||
            // iPhone device
 | 
			
		||||
            function isPhone(ua) {
 | 
			
		||||
                if (getDeviceUA(ua)[0] === "iPhone") {
 | 
			
		||||
                    return true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Returns the orientation of the device based on the
 | 
			
		||||
            // device's window dimensions
 | 
			
		||||
            function getOrientation() {
 | 
			
		||||
                if ($window.outerWidth > $window.outerHeight) {
 | 
			
		||||
                    return "landscape";
 | 
			
		||||
                } else if ($window.outerWidth < $window.outerHeight) {
 | 
			
		||||
                    return "portrait";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
         
 | 
			
		||||
            return {
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns the orientation for the user's device
 | 
			
		||||
                 */
 | 
			
		||||
                getOrientation: getOrientation,
 | 
			
		||||
                
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns the a boolean checking if the user is
 | 
			
		||||
                 * on a mobile or non-mobile device. (mobile: true,
 | 
			
		||||
                 * non-mobile: false)
 | 
			
		||||
                 */
 | 
			
		||||
                isMobile: isMobile,
 | 
			
		||||
                
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns the a boolean checking if the user is on
 | 
			
		||||
                 * a phone device. (phone: true, non-phone: false)
 | 
			
		||||
                 */
 | 
			
		||||
                isPhone: isPhone
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return AgentService;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -64,7 +64,7 @@ define(
 | 
			
		||||
                        "index.html#" + urlForLocation(mode, domainObject) + viewPath;
 | 
			
		||||
                return newTabPath;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
             
 | 
			
		||||
            return {
 | 
			
		||||
               /**
 | 
			
		||||
                 * Returns the Url path for a specific domain object
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ define(
 | 
			
		||||
        describe("The tree node controller", function () {
 | 
			
		||||
            var mockScope,
 | 
			
		||||
                mockTimeout,
 | 
			
		||||
                mockAgentService,
 | 
			
		||||
                controller;
 | 
			
		||||
 | 
			
		||||
            function TestObject(id, context) {
 | 
			
		||||
@@ -43,7 +44,8 @@ define(
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockScope = jasmine.createSpyObj("$scope", ["$watch", "$on"]);
 | 
			
		||||
                mockTimeout = jasmine.createSpy("$timeout");
 | 
			
		||||
                controller = new TreeNodeController(mockScope, mockTimeout);
 | 
			
		||||
                mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
 | 
			
		||||
                controller = new TreeNodeController(mockScope, mockTimeout, mockAgentService);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows tracking of expansion state", function () {
 | 
			
		||||
@@ -183,6 +185,12 @@ define(
 | 
			
		||||
                expect(controller.isSelected()).toBeFalsy();
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("check if tree node is in a mobile device", function () {
 | 
			
		||||
                if (controller) {
 | 
			
		||||
                    controller.checkMobile();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										74
									
								
								platform/commonUI/general/test/services/AgentServiceSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								platform/commonUI/general/test/services/AgentServiceSpec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/services/AgentService"],
 | 
			
		||||
    function (AgentService) {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        describe("The url service", function () {
 | 
			
		||||
            var agentService,
 | 
			
		||||
                mockWindow,
 | 
			
		||||
                mockNavigator;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                // Creates a mockLocation, used to 
 | 
			
		||||
                // do the view search
 | 
			
		||||
                mockWindow = jasmine.createSpyObj(
 | 
			
		||||
                    "$window",
 | 
			
		||||
                    [ "outerWidth", "outerHeight" ]
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockNavigator = jasmine.createSpyObj(
 | 
			
		||||
                    "navigator",
 | 
			
		||||
                    [ "userAgent" ]
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                agentService = new AgentService(mockWindow);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("get current device user agent", function () {
 | 
			
		||||
                mockNavigator.userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36";
 | 
			
		||||
                agentService.isMobile(mockNavigator.userAgent);
 | 
			
		||||
                agentService.isPhone(mockNavigator.userAgent);
 | 
			
		||||
                mockNavigator.userAgent = "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53";
 | 
			
		||||
                agentService.isMobile(mockNavigator.userAgent);
 | 
			
		||||
                mockNavigator.userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53";
 | 
			
		||||
                agentService.isPhone(mockNavigator.userAgent);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("get orientation of the current device", function () {
 | 
			
		||||
                mockWindow.outerWidth = 768;
 | 
			
		||||
                mockWindow.outerHeight = 1024;
 | 
			
		||||
                agentService.getOrientation();
 | 
			
		||||
                
 | 
			
		||||
                mockWindow.outerWidth = 1024;
 | 
			
		||||
                mockWindow.outerHeight = 768;
 | 
			
		||||
                agentService.getOrientation();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -91,7 +91,7 @@ define(
 | 
			
		||||
            
 | 
			
		||||
            it("get url for a new tab using domainObject and mode", function () {
 | 
			
		||||
                urlService.urlForNewTab(mockMode, mockDomainObject);
 | 
			
		||||
            });            
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -13,6 +13,7 @@
 | 
			
		||||
    "directives/MCTDrag",
 | 
			
		||||
    "directives/MCTResize",
 | 
			
		||||
    "directives/MCTScroll",
 | 
			
		||||
    "services/AgentService",
 | 
			
		||||
    "services/UrlService",
 | 
			
		||||
    "StyleSheetLoader"
 | 
			
		||||
]
 | 
			
		||||
@@ -24,9 +24,19 @@
 | 
			
		||||
                "implementation": "gestures/InfoGesture.js",
 | 
			
		||||
                "depends": [
 | 
			
		||||
                    "$timeout",
 | 
			
		||||
                    "agentService",
 | 
			
		||||
                    "infoService",
 | 
			
		||||
                    "INFO_HOVER_DELAY"
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "infobutton",
 | 
			
		||||
                "implementation": "gestures/InfoButtonGesture.js",
 | 
			
		||||
                "depends": [
 | 
			
		||||
                    "$document",
 | 
			
		||||
                    "agentService",
 | 
			
		||||
                    "infoService"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "services": [
 | 
			
		||||
@@ -37,15 +47,23 @@
 | 
			
		||||
                    "$compile",
 | 
			
		||||
                    "$document",
 | 
			
		||||
                    "$window",
 | 
			
		||||
                    "$rootScope"
 | 
			
		||||
                    "$rootScope",
 | 
			
		||||
                    "agentService"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        ],  
 | 
			
		||||
        "constants": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "INFO_HOVER_DELAY",
 | 
			
		||||
                "value": 2000
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "representations": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "info-button",
 | 
			
		||||
                "templateUrl": "templates/info-button.html",
 | 
			
		||||
                "gestures": [ "infobutton" ]
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								platform/commonUI/inspect/res/templates/info-button.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								platform/commonUI/inspect/res/templates/info-button.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<!--The icon for the info button appearing in a grid item (list in folder)-->
 | 
			
		||||
<div>
 | 
			
		||||
    <a class='ui-symbol icon mobile-info'>i</a>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										123
									
								
								platform/commonUI/inspect/src/gestures/InfoButtonGesture.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								platform/commonUI/inspect/src/gestures/InfoButtonGesture.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The `info` gesture displays domain object metadata in a
 | 
			
		||||
         * bubble on hover.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param $document Angular's `$document`
 | 
			
		||||
         * @param {InfoService} infoService a service which shows info bubbles
 | 
			
		||||
         * @param element jqLite-wrapped DOM element
 | 
			
		||||
         * @param {DomainObject} domainObject the domain object for which to
 | 
			
		||||
         *        show information
 | 
			
		||||
         */
 | 
			
		||||
        function InfoGestureButton($document, agentService, infoService, element, domainObject) {
 | 
			
		||||
            var dismissBubble,
 | 
			
		||||
                touchPosition,
 | 
			
		||||
                scopeOff,
 | 
			
		||||
                body = $document.find('body');
 | 
			
		||||
 | 
			
		||||
            function trackPosition(event) {
 | 
			
		||||
                // Record touch position, so bubble can be shown at latest
 | 
			
		||||
                // touch position, also offset by 22px to left (accounts for
 | 
			
		||||
                // a finger-sized touch on the info button)
 | 
			
		||||
                touchPosition = [ event.clientX - 22, event.clientY ];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Hides the bubble and detaches the
 | 
			
		||||
            // body hidebubble listener
 | 
			
		||||
            function hideBubble() {
 | 
			
		||||
                // If a bubble is showing, dismiss it
 | 
			
		||||
                if (dismissBubble) {
 | 
			
		||||
                    dismissBubble();
 | 
			
		||||
                    dismissBubble = undefined;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Detaches body touch listener
 | 
			
		||||
                body.off('touchstart', hideBubble);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Displays the bubble by tracking position of
 | 
			
		||||
            // touch, using infoService to display the bubble,
 | 
			
		||||
            // and then on any body touch the bubble is dismissed
 | 
			
		||||
            function showBubble(event) {
 | 
			
		||||
                trackPosition(event);
 | 
			
		||||
                
 | 
			
		||||
                // Show the bubble, but on any touchstart on the
 | 
			
		||||
                // body (anywhere) call hidebubble
 | 
			
		||||
                dismissBubble = infoService.display(
 | 
			
		||||
                    "info-table",
 | 
			
		||||
                    domainObject.getModel().name,
 | 
			
		||||
                    domainObject.useCapability('metadata'),
 | 
			
		||||
                    touchPosition
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                // On any touch on the body, default body touches/events
 | 
			
		||||
                // are prevented, the bubble is dismissed, and the touchstart
 | 
			
		||||
                // body event is unbound, reallowing gestures
 | 
			
		||||
                body.on('touchstart', function (event) {
 | 
			
		||||
                    event.preventDefault();
 | 
			
		||||
                    hideBubble();
 | 
			
		||||
                    body.unbind('touchstart');
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Checks if you are on a mobile device, if the device is
 | 
			
		||||
            // mobile (agentService.isMobile() = true), then
 | 
			
		||||
            // the a click on something (info button) brings up 
 | 
			
		||||
            // the bubble
 | 
			
		||||
            if (agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                element.on('click', showBubble);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Also make sure we dismiss bubble if representation is destroyed
 | 
			
		||||
            // before the mouse actually leaves it
 | 
			
		||||
            scopeOff = element.scope().$on('$destroy', hideBubble);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                /**
 | 
			
		||||
                 * Detach any event handlers associated with this gesture.
 | 
			
		||||
                 * @memberof InfoGesture
 | 
			
		||||
                 * @method
 | 
			
		||||
                 */
 | 
			
		||||
                destroy: function () {
 | 
			
		||||
                    // Dismiss any active bubble...
 | 
			
		||||
                    hideBubble();
 | 
			
		||||
                    // ...and detach listeners
 | 
			
		||||
                    element.off('click', showBubble);
 | 
			
		||||
                    scopeOff();
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return InfoGestureButton;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
);
 | 
			
		||||
@@ -38,7 +38,7 @@ define(
 | 
			
		||||
         * @param {DomainObject} domainObject the domain object for which to
 | 
			
		||||
         *        show information
 | 
			
		||||
         */
 | 
			
		||||
        function InfoGesture($timeout, infoService, DELAY, element, domainObject) {
 | 
			
		||||
        function InfoGesture($timeout, agentService, infoService, DELAY, element, domainObject) {
 | 
			
		||||
            var dismissBubble,
 | 
			
		||||
                pendingBubble,
 | 
			
		||||
                mousePosition,
 | 
			
		||||
@@ -71,7 +71,7 @@ define(
 | 
			
		||||
 | 
			
		||||
            function showBubble(event) {
 | 
			
		||||
                trackPosition(event);
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
                // Also need to track position during hover
 | 
			
		||||
                element.on('mousemove', trackPosition);
 | 
			
		||||
 | 
			
		||||
@@ -85,14 +85,20 @@ define(
 | 
			
		||||
                        mousePosition
 | 
			
		||||
                    );
 | 
			
		||||
                    element.off('mousemove', trackPosition);
 | 
			
		||||
 | 
			
		||||
                    pendingBubble = undefined;
 | 
			
		||||
                }, DELAY);
 | 
			
		||||
 | 
			
		||||
                element.on('mouseleave', hideBubble);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Show bubble (on a timeout) on mouse over
 | 
			
		||||
            element.on('mouseenter', showBubble);
 | 
			
		||||
            
 | 
			
		||||
            // Checks if you are on a mobile device, if the device is
 | 
			
		||||
            // not mobile (agentService.isMobile() = false), then
 | 
			
		||||
            // the pendingBubble and therefore hovering is allowed
 | 
			
		||||
            if (!agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                // Show bubble (on a timeout) on mouse over
 | 
			
		||||
                element.on('mouseenter', showBubble);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Also make sure we dismiss bubble if representation is destroyed
 | 
			
		||||
            // before the mouse actually leaves it
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ define(
 | 
			
		||||
         * Displays informative content ("info bubbles") for the user.
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function InfoService($compile, $document, $window, $rootScope) {
 | 
			
		||||
        function InfoService($compile, $document, $window, $rootScope, agentService) {
 | 
			
		||||
 | 
			
		||||
            function display(templateKey, title, content, position) {
 | 
			
		||||
                var body = $document.find('body'),
 | 
			
		||||
@@ -54,22 +54,33 @@ define(
 | 
			
		||||
                // Create the context menu
 | 
			
		||||
                bubble = $compile(BUBBLE_TEMPLATE)(scope);
 | 
			
		||||
 | 
			
		||||
                // Position the bubble
 | 
			
		||||
                // Position the bubble:
 | 
			
		||||
                // Phone: On a phone the bubble is specifically positioned
 | 
			
		||||
                //  so that it takes up the width of the screen.
 | 
			
		||||
                // Tablet/Desktop: On other devices with larger screens, the
 | 
			
		||||
                //  info bubble positioned as normal (with triangle pointing 
 | 
			
		||||
                //  to where clicked or pressed)
 | 
			
		||||
                bubble.css('position', 'absolute');
 | 
			
		||||
                if (goLeft) {
 | 
			
		||||
                    bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
 | 
			
		||||
                if (agentService.isPhone(navigator.userAgent)) {
 | 
			
		||||
                    bubble.css('right', '0px');
 | 
			
		||||
                    bubble.css('left', '0px');
 | 
			
		||||
                    bubble.css('top', 'auto');
 | 
			
		||||
                    bubble.css('bottom', '25px');
 | 
			
		||||
                } else {
 | 
			
		||||
                    bubble.css('left', position[0] + OFFSET[0] + 'px');
 | 
			
		||||
                    if (goLeft) {
 | 
			
		||||
                        bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
 | 
			
		||||
                    } else {
 | 
			
		||||
                        bubble.css('left', position[0] + OFFSET[0] + 'px');
 | 
			
		||||
                    }
 | 
			
		||||
                    if (goUp) {
 | 
			
		||||
                        bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
 | 
			
		||||
                    } else {
 | 
			
		||||
                        bubble.css('top', position[1] + OFFSET[1] + 'px');
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if (goUp) {
 | 
			
		||||
                    bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
 | 
			
		||||
                } else {
 | 
			
		||||
                    bubble.css('top', position[1] + OFFSET[1] + 'px');
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Add the menu to the body
 | 
			
		||||
                body.append(bubble);
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
                // Return a function to dismiss the bubble
 | 
			
		||||
                return function () { bubble.remove(); };
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										145
									
								
								platform/commonUI/inspect/test/gestures/InfoButtonGestureSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								platform/commonUI/inspect/test/gestures/InfoButtonGestureSpec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['../../src/gestures/InfoButtonGesture'],
 | 
			
		||||
    function (InfoButtonGesture) {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        describe("The info button gesture", function () {
 | 
			
		||||
            var mockTimeout,
 | 
			
		||||
                mockDocument,
 | 
			
		||||
                mockBody,
 | 
			
		||||
                mockAgentService,
 | 
			
		||||
                mockInfoService,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockEvent,
 | 
			
		||||
                mockScope,
 | 
			
		||||
                mockOff,
 | 
			
		||||
                testMetadata,
 | 
			
		||||
                mockPromise,
 | 
			
		||||
                mockHide,
 | 
			
		||||
                gesture,
 | 
			
		||||
                fireGesture,
 | 
			
		||||
                fireDismissGesture;
 | 
			
		||||
            
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockTimeout = jasmine.createSpy('$timeout');
 | 
			
		||||
                mockDocument = jasmine.createSpyObj('$document', ['find']);
 | 
			
		||||
                mockBody = jasmine.createSpyObj('body', [ 'on', 'off', 'scope', 'css', 'unbind' ]);
 | 
			
		||||
                mockDocument.find.andReturn(mockBody);
 | 
			
		||||
                mockAgentService = jasmine.createSpyObj('agentService', ['isMobile', 'isPhone']);
 | 
			
		||||
                mockInfoService = jasmine.createSpyObj(
 | 
			
		||||
                    'infoService',
 | 
			
		||||
                    [ 'display' ]
 | 
			
		||||
                );
 | 
			
		||||
                mockElement = jasmine.createSpyObj(
 | 
			
		||||
                    'element',
 | 
			
		||||
                    [ 'on', 'off', 'scope', 'css' ]
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    'domainObject',
 | 
			
		||||
                    [ 'getId', 'getCapability', 'useCapability', 'getModel' ]
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockEvent = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
 | 
			
		||||
                mockEvent.pageX = 0;
 | 
			
		||||
                mockEvent.pageY = 0;
 | 
			
		||||
                mockScope = jasmine.createSpyObj('$scope', [ '$on' ]);
 | 
			
		||||
                mockOff = jasmine.createSpy('$off');
 | 
			
		||||
                testMetadata = [ { name: "Test name", value: "Test value" } ];
 | 
			
		||||
                mockHide = jasmine.createSpy('hide');
 | 
			
		||||
 | 
			
		||||
                mockDomainObject.getModel.andReturn({ name: "Test Object" });
 | 
			
		||||
                mockDomainObject.useCapability.andCallFake(function (c) {
 | 
			
		||||
                    return (c === 'metadata') ? testMetadata : undefined;
 | 
			
		||||
                });
 | 
			
		||||
                mockElement.scope.andReturn(mockScope);
 | 
			
		||||
                mockScope.$on.andReturn(mockOff);
 | 
			
		||||
                mockInfoService.display.andReturn(mockHide);
 | 
			
		||||
                mockAgentService.isMobile.andReturn(true);
 | 
			
		||||
                gesture = new InfoButtonGesture(
 | 
			
		||||
                    mockDocument,
 | 
			
		||||
                    mockAgentService,
 | 
			
		||||
                    mockInfoService,
 | 
			
		||||
                    mockElement,
 | 
			
		||||
                    mockDomainObject
 | 
			
		||||
                );
 | 
			
		||||
                fireGesture =  mockElement.on.mostRecentCall.args[1];
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("expect click on the representation", function () {
 | 
			
		||||
                // Fires a click call on element and then
 | 
			
		||||
                // expects the click to have happened
 | 
			
		||||
                fireGesture(mockEvent);
 | 
			
		||||
                expect(mockElement.on).toHaveBeenCalledWith(
 | 
			
		||||
                    "click",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("expect click then dismiss on the representation", function () {
 | 
			
		||||
                // Fire the click and then expect the click
 | 
			
		||||
                fireGesture(mockEvent);
 | 
			
		||||
                expect(mockElement.on).toHaveBeenCalledWith(
 | 
			
		||||
                    "click",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                // Get the touch start on the body
 | 
			
		||||
                // and fire the dismiss gesture
 | 
			
		||||
                fireDismissGesture =  mockBody.on.mostRecentCall.args[1];
 | 
			
		||||
                fireDismissGesture(mockEvent);
 | 
			
		||||
                // Expect Body to have been touched, event.preventDefault()
 | 
			
		||||
                // to be called, then the mockBody listener to be detached
 | 
			
		||||
                // lastly unbind the touchstart used to dismiss so other 
 | 
			
		||||
                // events can be called
 | 
			
		||||
                expect(mockBody.on).toHaveBeenCalledWith(
 | 
			
		||||
                    "touchstart",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
                expect(mockEvent.preventDefault).toHaveBeenCalled();
 | 
			
		||||
                expect(mockBody.off).toHaveBeenCalledWith(
 | 
			
		||||
                    "touchstart",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
                expect(mockBody.unbind).toHaveBeenCalledWith(
 | 
			
		||||
                    'touchstart'
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("detaches a callback for info bubble events when destroyed", function () {
 | 
			
		||||
                expect(mockElement.off).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                gesture.destroy();
 | 
			
		||||
 | 
			
		||||
                expect(mockElement.off).toHaveBeenCalledWith(
 | 
			
		||||
                    "click",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -28,6 +28,7 @@ define(
 | 
			
		||||
 | 
			
		||||
        describe("The info gesture", function () {
 | 
			
		||||
            var mockTimeout,
 | 
			
		||||
                mockAgentService,
 | 
			
		||||
                mockInfoService,
 | 
			
		||||
                testDelay = 12321,
 | 
			
		||||
                mockElement,
 | 
			
		||||
@@ -50,6 +51,7 @@ define(
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockTimeout = jasmine.createSpy('$timeout');
 | 
			
		||||
                mockTimeout.cancel = jasmine.createSpy('cancel');
 | 
			
		||||
                mockAgentService = jasmine.createSpyObj('agentService', ['isMobile']);
 | 
			
		||||
                mockInfoService = jasmine.createSpyObj(
 | 
			
		||||
                    'infoService',
 | 
			
		||||
                    [ 'display' ]
 | 
			
		||||
@@ -79,6 +81,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                gesture = new InfoGesture(
 | 
			
		||||
                    mockTimeout,
 | 
			
		||||
                    mockAgentService,
 | 
			
		||||
                    mockInfoService,
 | 
			
		||||
                    testDelay,
 | 
			
		||||
                    mockElement,
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ define(
 | 
			
		||||
                mockDocument,
 | 
			
		||||
                testWindow,
 | 
			
		||||
                mockRootScope,
 | 
			
		||||
                mockAgentService,
 | 
			
		||||
                mockCompiledTemplate,
 | 
			
		||||
                testScope,
 | 
			
		||||
                mockBody,
 | 
			
		||||
@@ -42,6 +43,7 @@ define(
 | 
			
		||||
                mockDocument = jasmine.createSpyObj('$document', ['find']);
 | 
			
		||||
                testWindow = { innerWidth: 1000, innerHeight: 100 };
 | 
			
		||||
                mockRootScope = jasmine.createSpyObj('$rootScope', ['$new']);
 | 
			
		||||
                mockAgentService = jasmine.createSpyObj('agentService', ['isMobile', 'isPhone']);
 | 
			
		||||
                mockCompiledTemplate = jasmine.createSpy('template');
 | 
			
		||||
                testScope = {};
 | 
			
		||||
                mockBody = jasmine.createSpyObj('body', ['append']);
 | 
			
		||||
@@ -58,7 +60,8 @@ define(
 | 
			
		||||
                    mockCompile,
 | 
			
		||||
                    mockDocument,
 | 
			
		||||
                    testWindow,
 | 
			
		||||
                    mockRootScope
 | 
			
		||||
                    mockRootScope,
 | 
			
		||||
                    mockAgentService
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -124,6 +127,18 @@ define(
 | 
			
		||||
                        (40 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                it("when on phone device, positioning is always on bottom", function () {
 | 
			
		||||
                    mockAgentService.isPhone.andReturn(true);
 | 
			
		||||
                    service = new InfoService(
 | 
			
		||||
                        mockCompile,
 | 
			
		||||
                        mockDocument,
 | 
			
		||||
                        testWindow,
 | 
			
		||||
                        mockRootScope,
 | 
			
		||||
                        mockAgentService
 | 
			
		||||
                    );
 | 
			
		||||
                    service.display('', '', {}, [0, 0]);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
[
 | 
			
		||||
    "gestures/InfoGesture",
 | 
			
		||||
    "gestures/InfoButtonGesture",
 | 
			
		||||
    "services/InfoService"
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								platform/features/plot-reborn/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								platform/features/plot-reborn/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
# plot-reborn
 | 
			
		||||
 | 
			
		||||
The `plot-reborn` bundle provides directives for composing plot based views.
 | 
			
		||||
It also exposes domain objects for plotting telemetry points.
 | 
			
		||||
 | 
			
		||||
## Views
 | 
			
		||||
 | 
			
		||||
* OverlayPlot: can be used on any domain object that has or delegates a 
 | 
			
		||||
    telemetry capability.
 | 
			
		||||
 | 
			
		||||
* StackedPlot: can be used on any domain object that delegates telemetry or 
 | 
			
		||||
    delegates composition of elements that have telemetry.
 | 
			
		||||
 | 
			
		||||
## Directives
 | 
			
		||||
 | 
			
		||||
* `mct-chart`: an element that takes `series`, `viewport`, and
 | 
			
		||||
    `rectangles` and plots the data.  Adding points to a series after it has 
 | 
			
		||||
    been initially plotted can be done either by recreating the series object
 | 
			
		||||
    or by broadcasting "series:data:add" with arguments `event`, `seriesIndex`, 
 | 
			
		||||
    `points`.  This will append `points` to the `series` at index `seriesIndex`.
 | 
			
		||||
 | 
			
		||||
* `mct-plot`: A directive that wraps a mct-chart and handles user interactions
 | 
			
		||||
    with that plot.  It emits events that a parent view can use for coordinating
 | 
			
		||||
    functionality:
 | 
			
		||||
    * emits a `user:viewport:change:start` event when the viewport begins being
 | 
			
		||||
        changed by a user, to allow any parent controller to prevent viewport 
 | 
			
		||||
        modifications while the user is interacting with the plot.
 | 
			
		||||
    * emits a `user:viewport:change:end` event when the user has finished
 | 
			
		||||
        changing the viewport.  This allows a controller on a parent scope to
 | 
			
		||||
        track viewport history and provide any necessary functionality
 | 
			
		||||
        around viewport changes, e.g. viewport history.
 | 
			
		||||
 | 
			
		||||
* `mct-overlay-plot`: A directive that takes `domainObject` and plots either a
 | 
			
		||||
    single series of data (in the case of a single telemetry object) or multiple
 | 
			
		||||
    series of data (in the case of a object which delegates telemetry).
 | 
			
		||||
 | 
			
		||||
## Controllers
 | 
			
		||||
 | 
			
		||||
NOTE: this section not accurate.  Essentially, these controllers format data for
 | 
			
		||||
the mct-chart directive.  They also handle live viewport updating, as well as
 | 
			
		||||
managing all transformations from domain objects to views.
 | 
			
		||||
 | 
			
		||||
* StackPlotController: Uses the composition capability of a StackPlot domain 
 | 
			
		||||
    object to retrieve SubPlots and render them with individual PlotControllers.
 | 
			
		||||
* PlotController: Uses either a domain object that delegates telemetry or a 
 | 
			
		||||
    domain object with telemetry to and feeds that data to the mct-chart 
 | 
			
		||||
    directive.
 | 
			
		||||
 | 
			
		||||
## TODOS:
 | 
			
		||||
 | 
			
		||||
* [ ] Re-implement history stack.
 | 
			
		||||
* [ ] Re-implement plot pallette.
 | 
			
		||||
* [ ] Re-implement stacked plot viewport synchronization (share viewport object)
 | 
			
		||||
* [ ] Other things?
 | 
			
		||||
* [ ] Handle edge cases with marquee zoom/panning.
 | 
			
		||||
* [ ] Tidy code.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										101
									
								
								platform/features/plot-reborn/bundle.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								platform/features/plot-reborn/bundle.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "Plot view for telemetry, reborn",
 | 
			
		||||
    "extensions": {
 | 
			
		||||
        "views": [
 | 
			
		||||
            {
 | 
			
		||||
                "name": "Plot",
 | 
			
		||||
                "key": "plot-single",
 | 
			
		||||
                "glyph": "6",
 | 
			
		||||
                "templateUrl": "templates/plot.html",
 | 
			
		||||
                "needs": ["telemetry"],
 | 
			
		||||
                "uses": ["composition"],
 | 
			
		||||
                "delegation": false
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "name": "Overlay Plot",
 | 
			
		||||
                "key": "plot",
 | 
			
		||||
                "glyph": "6",
 | 
			
		||||
                "templateUrl": "templates/plot.html",
 | 
			
		||||
                "needs": ["telemetry", "composition"],
 | 
			
		||||
                "uses": ["composition"],
 | 
			
		||||
                "delegation": true
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "name": "Stacked Plot",
 | 
			
		||||
                "key": "stackedPlot",
 | 
			
		||||
                "glyph": "6",
 | 
			
		||||
                "templateUrl": "templates/stacked-plot.html",
 | 
			
		||||
                "needs": ["composition", "delegation"],
 | 
			
		||||
                "uses": ["composition"],
 | 
			
		||||
                "gestures": [ "drop" ],
 | 
			
		||||
                "delegation": true
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "directives": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "mctChart",
 | 
			
		||||
                "implementation": "directives/MCTChart.js",
 | 
			
		||||
                "depends": [ "$interval", "$log", "agentService" ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "mctPlot",
 | 
			
		||||
                "implementation": "directives/MCTPlot.js",
 | 
			
		||||
                "depends": [],
 | 
			
		||||
                "templateUrl": "templates/mct-plot.html"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "mctOverlayPlot",
 | 
			
		||||
                "implementation": "directives/MCTOverlayPlot.js",
 | 
			
		||||
                "depends": []
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "mctPinch",
 | 
			
		||||
                "implementation": "directives/MCTPinch.js",
 | 
			
		||||
                "depends": [ "agentService" ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "controllers": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "PlotController",
 | 
			
		||||
                "implementation": "controllers/PlotController.js",
 | 
			
		||||
                "depends": [ "$scope", "colorService", "agentService"]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "StackedPlotController",
 | 
			
		||||
                "implementation": "controllers/StackedPlotController.js",
 | 
			
		||||
                "depends": [ "$scope" ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "types": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "telemetry.plot.overlay",
 | 
			
		||||
                "name": "Overlay Plot",
 | 
			
		||||
                "glyph": "t",
 | 
			
		||||
                "description": "A plot containing one or more telemetry elements.",
 | 
			
		||||
                "delegates": ["telemetry"],
 | 
			
		||||
                "features": "creation",
 | 
			
		||||
                "contains": [{"has": "telemetry"}],
 | 
			
		||||
                "model": {"composition": []},
 | 
			
		||||
                "properties": []
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "telemetry.plot.stacked",
 | 
			
		||||
                "name": "Stacked Plot",
 | 
			
		||||
                "glyph": "t",
 | 
			
		||||
                "description": "A stacked plot of overlay plots.",
 | 
			
		||||
                "delegates": ["delegation"],
 | 
			
		||||
                "features": "creation",
 | 
			
		||||
                "contains": ["telemetry.plot.overlay", {"has": "telemetry"}],
 | 
			
		||||
                "model": {"composition": []},
 | 
			
		||||
                "properties": []
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "services": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "colorService",
 | 
			
		||||
                "implementation": "services/ColorService.js",
 | 
			
		||||
                "description": "Provides objects for working with colors."
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								platform/features/plot-reborn/res/templates/mct-plot.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								platform/features/plot-reborn/res/templates/mct-plot.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
<!--TODO: Don't require plotcontroller here. -->
 | 
			
		||||
<div class="gl-plot">
 | 
			
		||||
    <div class="gl-plot-legend">
 | 
			
		||||
        <span class="plot-legend-item"
 | 
			
		||||
              ng-repeat="series in series track by $index">
 | 
			
		||||
            <span class="plot-color-swatch"
 | 
			
		||||
                  ng-style="{ 'background-color': series.color.asHexString() }">
 | 
			
		||||
            </span>
 | 
			
		||||
            <span class="title-label">{{ series.name }}</span>
 | 
			
		||||
        </span>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="gl-plot-coords"
 | 
			
		||||
         ng-if="mouseCoordinates">
 | 
			
		||||
        {{ displayableDomain(mouseCoordinates.positionAsPlotPoint.domain)  }},
 | 
			
		||||
        {{ displayableRange(mouseCoordinates.positionAsPlotPoint.range) }}
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="gl-plot-axis-area gl-plot-y">
 | 
			
		||||
 | 
			
		||||
        <div class="gl-plot-label gl-plot-y-label">
 | 
			
		||||
            {{ axes.range.label}}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div ng-repeat="tick in axes.range.ticks track by $index"
 | 
			
		||||
             class="gl-plot-tick gl-plot-y-tick-label"
 | 
			
		||||
             ng-style="{ top: (100 * $index / (axes.range.ticks.length - 1)) + '%' }"
 | 
			
		||||
             style="margin-top: -0.50em;">
 | 
			
		||||
            {{ displayableRange(tick) }}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="gl-plot-display-area">
 | 
			
		||||
 | 
			
		||||
        <div class="gl-plot-hash hash-v"
 | 
			
		||||
             ng-repeat="tick in axes.domain.ticks track by $index"
 | 
			
		||||
             ng-style="{ left: (100 * $index / (axes.domain.ticks.length - 1)) + '%', height: '100%' }"
 | 
			
		||||
             ng-show="$index > 0 && $index < (axes.domain.ticks.length - 1)">
 | 
			
		||||
            <!--TODO: Show/hide using CSS? -->
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="gl-plot-hash hash-h"
 | 
			
		||||
             ng-repeat="tick in axes.range.ticks track by $index"
 | 
			
		||||
             ng-style="{ bottom: (100 * $index / (axes.range.ticks.length - 1)) + '%', width: '100%' }"
 | 
			
		||||
             ng-show="$index > 0 && $index < (axes.range.ticks.length - 1)">
 | 
			
		||||
             <!--TODO: Show/hide using CSS? -->
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
<!--        APPLY MCTPinch here-->
 | 
			
		||||
        <mct-chart series="series"
 | 
			
		||||
                   viewport="viewport"
 | 
			
		||||
                   rectangles="rectangles"
 | 
			
		||||
                   ng-mousemove="plot.trackMousePosition($event)"
 | 
			
		||||
                   ng-mouseleave="plot.untrackMousePosition()"
 | 
			
		||||
                   ng-mousedown="plot.startMarquee()"
 | 
			
		||||
                   ng-mouseup="plot.endMarquee()"
 | 
			
		||||
                   mct-pinch>
 | 
			
		||||
        </mct-chart>
 | 
			
		||||
 | 
			
		||||
        <span class="t-wait-spinner loading" ng-show="plot.isRequestPending()">
 | 
			
		||||
        </span>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="gl-plot-axis-area gl-plot-x">
 | 
			
		||||
        <div ng-repeat="tick in axes.domain.ticks track by $index"
 | 
			
		||||
             class="gl-plot-tick gl-plot-x-tick-label"
 | 
			
		||||
             ng-show="$index > 0 && $index < (axes.domain.ticks.length - 1)"
 | 
			
		||||
             ng-style="{ left: (100 * $index / (axes.domain.ticks.length - 1)) + '%' }">
 | 
			
		||||
            {{ displayableDomain(tick) }}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="gl-plot-label gl-plot-x-label">
 | 
			
		||||
            {{ axes.domain.label }}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										9
									
								
								platform/features/plot-reborn/res/templates/plot.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								platform/features/plot-reborn/res/templates/plot.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<span ng-controller="PlotController as controller">
 | 
			
		||||
    <mct-plot series="series"
 | 
			
		||||
              viewport="viewport"
 | 
			
		||||
              rectangles="rectangles"
 | 
			
		||||
              axes="axes"
 | 
			
		||||
              displayable-range="displayableRange"
 | 
			
		||||
              displayable-domain="displayableDomain">
 | 
			
		||||
    </mct-plot>
 | 
			
		||||
</span>
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
<span ng-controller="StackedPlotController as stackedPlot">
 | 
			
		||||
    <div class="gl-plot"
 | 
			
		||||
        ng-style="{ height: 100 / telemetryObjects.length + '%'}"
 | 
			
		||||
        ng-repeat="telemetryObject in telemetryObjects">
 | 
			
		||||
 | 
			
		||||
        <mct-overlay-plot domain-object="telemetryObject"></mct-overlay-plot>
 | 
			
		||||
    </div>
 | 
			
		||||
</span>
 | 
			
		||||
							
								
								
									
										239
									
								
								platform/features/plot-reborn/src/controllers/PlotController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								platform/features/plot-reborn/src/controllers/PlotController.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        // TODO: Store this in more accessible locations / retrieve from
 | 
			
		||||
        // domainObject metadata.
 | 
			
		||||
        var DOMAIN_INTERVAL = 2 * 60 * 1000; // Two minutes.
 | 
			
		||||
 | 
			
		||||
        function PlotController($scope, colorService, agentService) {
 | 
			
		||||
            var plotHistory = [],
 | 
			
		||||
                isLive = true,
 | 
			
		||||
                maxDomain = +new Date(),
 | 
			
		||||
                subscriptions = [],
 | 
			
		||||
                palette = new colorService.ColorPalette();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            function setToDefaultViewport() {
 | 
			
		||||
                // TODO: We shouldn't set the viewport until we have received data or something has given us a reasonable viewport.
 | 
			
		||||
                $scope.viewport = {
 | 
			
		||||
                    topLeft: {
 | 
			
		||||
                        domain: maxDomain - DOMAIN_INTERVAL,
 | 
			
		||||
                        range: 1
 | 
			
		||||
                    },
 | 
			
		||||
                    bottomRight: {
 | 
			
		||||
                        domain: maxDomain,
 | 
			
		||||
                        range: -1
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setToDefaultViewport();
 | 
			
		||||
 | 
			
		||||
            $scope.displayableRange = function (rangeValue) {
 | 
			
		||||
                // TODO: Call format function provided by domain object.
 | 
			
		||||
                return rangeValue;
 | 
			
		||||
            };
 | 
			
		||||
            $scope.displayableDomain = function (domainValue) {
 | 
			
		||||
                // TODO: Call format function provided by domain object.
 | 
			
		||||
                return new Date(domainValue).toUTCString();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            $scope.series = [];
 | 
			
		||||
 | 
			
		||||
            $scope.rectangles = [];
 | 
			
		||||
 | 
			
		||||
            function updateSeriesFromTelemetry(series, seriesIndex, telemetry) {
 | 
			
		||||
                var domainValue = telemetry.getDomainValue(
 | 
			
		||||
                        telemetry.getPointCount() - 1
 | 
			
		||||
                    ),
 | 
			
		||||
                    rangeValue = telemetry.getRangeValue(
 | 
			
		||||
                        telemetry.getPointCount() - 1
 | 
			
		||||
                    ),
 | 
			
		||||
                    newTelemetry;
 | 
			
		||||
                // Track the biggest domain we've seen for sticky-ness.
 | 
			
		||||
                maxDomain = Math.max(maxDomain, domainValue);
 | 
			
		||||
 | 
			
		||||
                newTelemetry = {
 | 
			
		||||
                    domain: domainValue,
 | 
			
		||||
                    range: rangeValue
 | 
			
		||||
                };
 | 
			
		||||
                series.data.push(newTelemetry);
 | 
			
		||||
                $scope.$broadcast('series:data:add', seriesIndex, [newTelemetry]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function subscribeToDomainObject(domainObject) {
 | 
			
		||||
                var telemetryCapability = domainObject.getCapability('telemetry'),
 | 
			
		||||
                    model = domainObject.getModel(),
 | 
			
		||||
                    series,
 | 
			
		||||
                    seriesIndex,
 | 
			
		||||
                    updater;
 | 
			
		||||
 | 
			
		||||
                series = {
 | 
			
		||||
                    name: model.name,
 | 
			
		||||
                    // TODO: Bring back PlotPalette.
 | 
			
		||||
                    color: palette.getColor($scope.series.length),
 | 
			
		||||
                    data: []
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                $scope.series.push(series);
 | 
			
		||||
                seriesIndex = $scope.series.indexOf(series);
 | 
			
		||||
 | 
			
		||||
                updater = updateSeriesFromTelemetry.bind(
 | 
			
		||||
                    null,
 | 
			
		||||
                    series,
 | 
			
		||||
                    seriesIndex
 | 
			
		||||
                );
 | 
			
		||||
                subscriptions.push(telemetryCapability.subscribe(updater));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function unlinkDomainObject() {
 | 
			
		||||
                subscriptions.forEach(function(subscription) {
 | 
			
		||||
                    subscription.unsubscribe();
 | 
			
		||||
                });
 | 
			
		||||
                subscriptions = [];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            function linkDomainObject(domainObject) {
 | 
			
		||||
                unlinkDomainObject();
 | 
			
		||||
                if (domainObject.hasCapability('telemetry')) {
 | 
			
		||||
                    subscribeToDomainObject(domainObject);
 | 
			
		||||
                } else if (domainObject.hasCapability('delegation')) {
 | 
			
		||||
                    // Makes no sense that we have to use a subscription to get domain objects associated with delegates (and their names).  We can map the same series generation code to telemetry delegates; Let's do that ourselves.
 | 
			
		||||
                    var subscribeToDelegates = function(delegates) {
 | 
			
		||||
                        return delegates.forEach(subscribeToDomainObject);
 | 
			
		||||
                        // TODO: Should return a promise.
 | 
			
		||||
                    };
 | 
			
		||||
                    domainObject
 | 
			
		||||
                        .getCapability('delegation')
 | 
			
		||||
                        .getDelegates('telemetry')
 | 
			
		||||
                        .then(subscribeToDelegates);
 | 
			
		||||
                        // TODO: should have a catch.
 | 
			
		||||
                } else {
 | 
			
		||||
                    throw new Error('Domain object type not supported.');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            function onUserViewportChangeStart() {
 | 
			
		||||
                // TODO: this is a great time to track a history entry.
 | 
			
		||||
                // Disable live mode so they have full control of viewport.
 | 
			
		||||
                plotHistory.push($scope.viewport);
 | 
			
		||||
 | 
			
		||||
                isLive = false;
 | 
			
		||||
                $scope.axes.domain.label = "Time (Manipulated)";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Returns the value of the left domain value
 | 
			
		||||
            // used when the right value has been adjusted and
 | 
			
		||||
            // a pan or zoom has occurred
 | 
			
		||||
            function getLeftInterval(intervalTL, intervalBR) {
 | 
			
		||||
                return intervalTL.domain + (maxDomain - intervalBR.domain);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Checks if the user is on mobile or desktop,
 | 
			
		||||
            // based on that returns the boolean value
 | 
			
		||||
            // if the chart should be snapped to the right
 | 
			
		||||
            // side of the screen
 | 
			
		||||
            function getSnapCheck(viewport, onMobile) {
 | 
			
		||||
                // Default amount within which to snap
 | 
			
		||||
                // for desktop version
 | 
			
		||||
                var snapPercent = 10;
 | 
			
		||||
 | 
			
		||||
                if(onMobile) {
 | 
			
		||||
                    // Smaller amount within which to snap
 | 
			
		||||
                    // for mobile version
 | 
			
		||||
                    snapPercent = 75;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return (Math.abs(maxDomain - viewport.bottomRight.domain) < (DOMAIN_INTERVAL/snapPercent));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Spans the chart to the right domain value to update the
 | 
			
		||||
            // chart live and keep up with the maxDomain
 | 
			
		||||
            function snapToRight() {
 | 
			
		||||
 | 
			
		||||
                // Sets the chart to being live and changes the
 | 
			
		||||
                // range name to show that the chart is updating
 | 
			
		||||
                isLive = true;
 | 
			
		||||
                $scope.axes.domain.label = "Time (Updating Live)";
 | 
			
		||||
 | 
			
		||||
                // Changes right domain value to maxDomain (value
 | 
			
		||||
                // of latest chart domain value)
 | 
			
		||||
                $scope.viewport.bottomRight.domain = maxDomain;
 | 
			
		||||
 | 
			
		||||
                // Adjusts the left domain value to keep up with the
 | 
			
		||||
                // right domain change by adding it to the current left domain
 | 
			
		||||
                $scope.viewport.topLeft.domain = getLeftInterval($scope.viewport.topLeft,
 | 
			
		||||
                    $scope.viewport.bottomRight);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // In the past what has happened is that the interval between the left and right domain
 | 
			
		||||
            // is set to 2 minutes all the time. And the range is -1 and 1 on update
 | 
			
		||||
            function onUserViewportChangeEnd(event, viewport) {
 | 
			
		||||
                // If the new viewport is "close enough" to the maxDomain then
 | 
			
		||||
                // enable live mode.  Set empirically to 10% of the domain
 | 
			
		||||
                // interval.
 | 
			
		||||
                // TODO: Better UX pattern for this.
 | 
			
		||||
 | 
			
		||||
                // Checks if the chart needs to snap to the right based on the
 | 
			
		||||
                // current device and where the right domain is located
 | 
			
		||||
                if (getSnapCheck(viewport, agentService.isMobile(navigator.userAgent))) {
 | 
			
		||||
                    snapToRight();
 | 
			
		||||
                } else {
 | 
			
		||||
 | 
			
		||||
                    // The viewport has been changed, but is not actively
 | 
			
		||||
                    // keeping up with the plot, therefore isLive = false
 | 
			
		||||
                    isLive = false;
 | 
			
		||||
                    $scope.axes.domain.label = "Time (Manipulated)";
 | 
			
		||||
                }
 | 
			
		||||
                plotHistory.push(viewport);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function viewportForMaxDomain() {
 | 
			
		||||
                 return {
 | 
			
		||||
                    topLeft: {
 | 
			
		||||
                        range: $scope.viewport.topLeft.range,
 | 
			
		||||
                        domain: getLeftInterval($scope.viewport.topLeft,
 | 
			
		||||
                            $scope.viewport.bottomRight)
 | 
			
		||||
                    },
 | 
			
		||||
                    bottomRight: {
 | 
			
		||||
                        range: $scope.viewport.bottomRight.range,
 | 
			
		||||
                        domain: maxDomain
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function followDataIfLive() {
 | 
			
		||||
                if (isLive) {
 | 
			
		||||
                    $scope.viewport = viewportForMaxDomain();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $scope.$on('series:data:add', followDataIfLive);
 | 
			
		||||
            $scope.$on('user:viewport:change:end', onUserViewportChangeEnd);
 | 
			
		||||
            $scope.$on('user:viewport:change:start', onUserViewportChangeStart);
 | 
			
		||||
            
 | 
			
		||||
            $scope.$watch('domainObject', linkDomainObject);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                historyBack: function() {
 | 
			
		||||
                    // TODO: Step History Back.
 | 
			
		||||
                },
 | 
			
		||||
                historyForward: function() {
 | 
			
		||||
                    // TODO: Step History Forward.
 | 
			
		||||
                },
 | 
			
		||||
                resetZoom: function() {
 | 
			
		||||
                    // TODO: Reset view to defaults.  Keep history stack alive?
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return PlotController;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
/*global define */
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        function StackedPlotController($scope) {
 | 
			
		||||
 | 
			
		||||
            $scope.telemetryObjects = [];
 | 
			
		||||
 | 
			
		||||
            var linkDomainObject = function(domainObject) {
 | 
			
		||||
                $scope.telemetryObjects = [];
 | 
			
		||||
                if (domainObject.hasCapability('telemetry')) {
 | 
			
		||||
                    $scope.telemetryObjects = [domainObject];
 | 
			
		||||
                } else if (domainObject.hasCapability('delegation')) {
 | 
			
		||||
 | 
			
		||||
                    var addObjectsIfCompatible = function(objects) {
 | 
			
		||||
                        objects.forEach(function(object) {
 | 
			
		||||
                            if (object.hasCapability('telemetry')) {
 | 
			
		||||
                                $scope.telemetryObjects.push(object);
 | 
			
		||||
                            } else if (object.hasCapability('delegation')) {
 | 
			
		||||
                                $scope.telemetryObjects.push(object);
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    };
 | 
			
		||||
                    domainObject
 | 
			
		||||
                        .useCapability('composition')
 | 
			
		||||
                        .then(addObjectsIfCompatible);
 | 
			
		||||
                        // TODO: should have a catch.
 | 
			
		||||
                } else {
 | 
			
		||||
                    throw new Error('Domain object type not supported.');
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            $scope.$watch('domainObject', linkDomainObject);
 | 
			
		||||
        }
 | 
			
		||||
        return StackedPlotController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										239
									
								
								platform/features/plot-reborn/src/directives/MCTChart.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								platform/features/plot-reborn/src/directives/MCTChart.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
/*global define,requestAnimationFrame,Float32Array*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module defining MCTChart. Created by vwoeltje on 11/12/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../draw/DrawLoader"],
 | 
			
		||||
    function (DrawLoader) {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        var TEMPLATE = "<canvas style='position: absolute; background: none; width: 100%; height: 100%;'></canvas>";
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Offsetter adjusts domain and range values by a fixed amount,
 | 
			
		||||
         * generally increasing the precision of the 32 bit float representation
 | 
			
		||||
         * required for plotting.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function Offsetter(domainOffset, rangeOffset) {
 | 
			
		||||
            this.domainOffset = domainOffset;
 | 
			
		||||
            this.rangeOffset = rangeOffset;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Offsetter.prototype.domain = function(dataDomain) {
 | 
			
		||||
            return dataDomain - this.domainOffset;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Offsetter.prototype.range = function(dataRange) {
 | 
			
		||||
            return dataRange - this.rangeOffset;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * MCTChart draws charts utilizing a drawAPI.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function MCTChart($interval, $log, agentService) {
 | 
			
		||||
 | 
			
		||||
            function linkChart($scope, $element) {
 | 
			
		||||
                var canvas = $element.find("canvas")[0],
 | 
			
		||||
                    isDestroyed = false,
 | 
			
		||||
                    activeInterval,
 | 
			
		||||
                    drawAPI,
 | 
			
		||||
                    lines = [],
 | 
			
		||||
                    offset;
 | 
			
		||||
 | 
			
		||||
                drawAPI = DrawLoader.getDrawAPI(canvas);
 | 
			
		||||
 | 
			
		||||
                if (!drawAPI) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function createOffset() {
 | 
			
		||||
                    if (offset) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (!$scope.viewport ||
 | 
			
		||||
                        !$scope.viewport.topLeft ||
 | 
			
		||||
                        !$scope.viewport.bottomRight) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    offset = new Offsetter(
 | 
			
		||||
                        $scope.viewport.topLeft.domain,
 | 
			
		||||
                        $scope.viewport.topLeft.range
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function lineFromSeries(series) {
 | 
			
		||||
                    // TODO: handle when lines get longer than 10,000 points.
 | 
			
		||||
                    // Each line allocates 10,000 points.  This should be more
 | 
			
		||||
                    // that we ever need, but we have to decide how to handle
 | 
			
		||||
                    // this at the higher level.  I imagine the plot controller
 | 
			
		||||
                    // should watch it's series and when they get huge, slice
 | 
			
		||||
                    // them in half and delete the oldest half.
 | 
			
		||||
                    //
 | 
			
		||||
                    // As long as the controller replaces $scope.series with a
 | 
			
		||||
                    // new series object, then this directive will
 | 
			
		||||
                    // automatically generate new arrays for those lines.
 | 
			
		||||
                    // In practice, the overhead of regenerating these lines
 | 
			
		||||
                    // appears minimal.
 | 
			
		||||
                    var lineBuffer = new Float32Array(20000),
 | 
			
		||||
                        i = 0;
 | 
			
		||||
                    for (i = 0; i < series.data.length; i++) {
 | 
			
		||||
                        lineBuffer[2*i] = offset.domain(series.data[i].domain);
 | 
			
		||||
                        lineBuffer[2*i+1] = offset.range(series.data[i].range);
 | 
			
		||||
                    }
 | 
			
		||||
                    return {
 | 
			
		||||
                        color: series.color,
 | 
			
		||||
                        buffer: lineBuffer,
 | 
			
		||||
                        pointCount: series.data.length
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function drawSeries() {
 | 
			
		||||
                    // TODO: Don't regenerate lines on each frame.
 | 
			
		||||
                    if (!$scope.series || !$scope.series.length) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    lines = $scope.series.map(lineFromSeries);
 | 
			
		||||
                    lines.forEach(function(line) {
 | 
			
		||||
                        drawAPI.drawLine(
 | 
			
		||||
                            line.buffer,
 | 
			
		||||
                            line.color.asRGBAArray(),
 | 
			
		||||
                            line.pointCount
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function drawRectangles() {
 | 
			
		||||
                    if ($scope.rectangles) {
 | 
			
		||||
                        $scope.rectangles.forEach(function(rect) {
 | 
			
		||||
                            drawAPI.drawSquare(
 | 
			
		||||
                                [
 | 
			
		||||
                                    offset.domain(rect.start.domain),
 | 
			
		||||
                                    offset.range(rect.start.range)
 | 
			
		||||
                                ],
 | 
			
		||||
                                [
 | 
			
		||||
                                    offset.domain(rect.end.domain),
 | 
			
		||||
                                    offset.range(rect.end.range)
 | 
			
		||||
                                ],
 | 
			
		||||
                                rect.color
 | 
			
		||||
                            );
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function updateViewport() {
 | 
			
		||||
                    var dimensions,
 | 
			
		||||
                        origin;
 | 
			
		||||
 | 
			
		||||
                    dimensions = [
 | 
			
		||||
                        Math.abs(
 | 
			
		||||
                            offset.domain($scope.viewport.topLeft.domain) -
 | 
			
		||||
                            offset.domain($scope.viewport.bottomRight.domain)
 | 
			
		||||
                        ),
 | 
			
		||||
                        Math.abs(
 | 
			
		||||
                            offset.range($scope.viewport.topLeft.range) -
 | 
			
		||||
                            offset.range($scope.viewport.bottomRight.range)
 | 
			
		||||
                        )
 | 
			
		||||
                    ];
 | 
			
		||||
 | 
			
		||||
                    origin = [
 | 
			
		||||
                        offset.domain(
 | 
			
		||||
                            $scope.viewport.topLeft.domain
 | 
			
		||||
                        ),
 | 
			
		||||
                        offset.range(
 | 
			
		||||
                            $scope.viewport.bottomRight.range
 | 
			
		||||
                        )
 | 
			
		||||
                    ];
 | 
			
		||||
 | 
			
		||||
                    drawAPI.setDimensions(
 | 
			
		||||
                        dimensions,
 | 
			
		||||
                        origin
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function onSeriesDataAdd(event, seriesIndex, points) {
 | 
			
		||||
                    var line = lines[seriesIndex];
 | 
			
		||||
                    points.forEach(function (point) {
 | 
			
		||||
                        line.buffer[2*line.pointCount] = offset.domain(point.domain);
 | 
			
		||||
                        line.buffer[2*line.pointCount+1] = offset.range(point.range);
 | 
			
		||||
                        line.pointCount += 1;
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                function redraw() {
 | 
			
		||||
                    if (isDestroyed) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    requestAnimationFrame(redraw);
 | 
			
		||||
                    canvas.width = canvas.offsetWidth;
 | 
			
		||||
                    canvas.height = canvas.offsetHeight;
 | 
			
		||||
                    drawAPI.clear();
 | 
			
		||||
                    createOffset();
 | 
			
		||||
                    if (!offset) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    updateViewport();
 | 
			
		||||
                    drawSeries();
 | 
			
		||||
                    drawRectangles();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                function drawIfResized() {
 | 
			
		||||
                    if (canvas.width !== canvas.offsetWidth ||
 | 
			
		||||
                            canvas.height !== canvas.offsetHeight) {
 | 
			
		||||
                        redraw();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function destroyChart() {
 | 
			
		||||
                    isDestroyed = true;
 | 
			
		||||
                    if (activeInterval) {
 | 
			
		||||
                        $interval.cancel(activeInterval);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Check for resize, on a timer, the timer is 15
 | 
			
		||||
                // on mobile (to allow quick refresh of drawing).
 | 
			
		||||
                if(agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                    activeInterval = $interval(drawIfResized, 15, false);
 | 
			
		||||
                } else {
 | 
			
		||||
                    activeInterval = $interval(drawIfResized, 1000, false);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $scope.$on('series:data:add', onSeriesDataAdd);
 | 
			
		||||
                redraw();
 | 
			
		||||
 | 
			
		||||
                // Stop checking for resize when $scope is destroyed
 | 
			
		||||
                $scope.$on("$destroy", destroyChart);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                // Apply directive only to $elements
 | 
			
		||||
                restrict: "E",
 | 
			
		||||
 | 
			
		||||
                // Template to use (a canvas $element)
 | 
			
		||||
                template: TEMPLATE,
 | 
			
		||||
 | 
			
		||||
                // Link function; set up $scope
 | 
			
		||||
                link: linkChart,
 | 
			
		||||
 | 
			
		||||
                // Initial, isolate $scope for the directive
 | 
			
		||||
                scope: {
 | 
			
		||||
                    draw: "=" ,
 | 
			
		||||
                    rectangles: "=",
 | 
			
		||||
                    series: "=",
 | 
			
		||||
                    viewport: "="
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return MCTChart;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define(function () {
 | 
			
		||||
        return function MCTOverlayPlot() {
 | 
			
		||||
            return {
 | 
			
		||||
                restrict: "E",
 | 
			
		||||
                templateUrl: 'platform/features/plot-reborn/res/templates/plot.html',
 | 
			
		||||
                scope: {
 | 
			
		||||
                    domainObject: "="
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										244
									
								
								platform/features/plot-reborn/src/directives/MCTPinch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								platform/features/plot-reborn/src/directives/MCTPinch.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,244 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        function MCTPinch(agentService) {
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             * Links the attributes with the
 | 
			
		||||
             * provided link function and nested
 | 
			
		||||
             * touch event functions
 | 
			
		||||
             */
 | 
			
		||||
            function link($scope, element) {
 | 
			
		||||
 | 
			
		||||
                // isPan and isPinch variables are set after the start
 | 
			
		||||
                // of a gestures and is checked over the change of that
 | 
			
		||||
                // gesture. These are used to differentiate gestures and
 | 
			
		||||
                // force only one type of gesture to be done at a time
 | 
			
		||||
                var isPan = false,
 | 
			
		||||
                    isPinch = false;
 | 
			
		||||
 | 
			
		||||
                // Returns position of touch event
 | 
			
		||||
                function trackPosition(event) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        clientX: event.clientX,
 | 
			
		||||
                        clientY: event.clientY
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Calculates the midpoint between two given
 | 
			
		||||
                // coordinates and returns it as coordinate object
 | 
			
		||||
                function calculateMidpoint(coordOne, coordTwo) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        clientX: (coordOne.clientX + coordTwo.clientX) / 2,
 | 
			
		||||
                        clientY: (coordOne.clientY + coordTwo.clientY) / 2
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Calculates the distance between two coordinates
 | 
			
		||||
                // and returns as number/integer value
 | 
			
		||||
                function calculateDistance(coordOne, coordTwo) {
 | 
			
		||||
                    return Math.sqrt(Math.pow(coordOne.clientX - coordTwo.clientX, 2) +
 | 
			
		||||
                        Math.pow(coordOne.clientY - coordTwo.clientY, 2));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Checks if the user is going to pan by checking the number
 | 
			
		||||
                // of touches on the screen (one touch means pan)
 | 
			
		||||
                function checkPan(event) {
 | 
			
		||||
                    return (event.changedTouches.length === 1) ||
 | 
			
		||||
                        (event.touches.length === 1);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Checks if the user is going to pinch by checking the number
 | 
			
		||||
                // of touches on the screen (two touches means pinch)
 | 
			
		||||
                function checkPinch(event) {
 | 
			
		||||
                    return (event.changedTouches.length === 2) ||
 | 
			
		||||
                        (event.touches.length === 2);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // On touch start the 'touch' is tracked and
 | 
			
		||||
                // the event is emitted through scope
 | 
			
		||||
                function touchStart(event) {
 | 
			
		||||
                    var touchPosition;
 | 
			
		||||
 | 
			
		||||
                    // If two touches or change touches are occurring
 | 
			
		||||
                    // than user is doing a pinch gesture
 | 
			
		||||
                    if (checkPinch(event)) {
 | 
			
		||||
 | 
			
		||||
                        // User has started pinch, sets isPinch and resets isPan
 | 
			
		||||
                        isPan = false;
 | 
			
		||||
                        isPinch = true;
 | 
			
		||||
 | 
			
		||||
                        // Position of both touches are tracked and saved in variable
 | 
			
		||||
                        touchPosition = [trackPosition(event.touches[0]),
 | 
			
		||||
                            trackPosition(event.touches[1])];
 | 
			
		||||
 | 
			
		||||
                        // Emits the start of the pinch and passes the
 | 
			
		||||
                        // touch coordinates (touches), the bounds of the
 | 
			
		||||
                        // event, the midpoint of both touch coorddinates,
 | 
			
		||||
                        // and the distance between the two touch coordinates
 | 
			
		||||
                        $scope.$emit('mct:pinch:start', {
 | 
			
		||||
                            touches: touchPosition,
 | 
			
		||||
                            bounds: event.target.getBoundingClientRect(),
 | 
			
		||||
                            midpoint: calculateMidpoint(touchPosition[0], touchPosition[1]),
 | 
			
		||||
                            distance: calculateDistance(touchPosition[0], touchPosition[1])
 | 
			
		||||
                        });
 | 
			
		||||
                        
 | 
			
		||||
                        // Stops other gestures/button clicks from being active
 | 
			
		||||
                        event.preventDefault();
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    // If one touch or change touch is occurring
 | 
			
		||||
                    // user is doing a single finger pan gesture
 | 
			
		||||
                    else if (checkPan(event)) {
 | 
			
		||||
 | 
			
		||||
                        // User has started pan, sets isPan and resets isPinch
 | 
			
		||||
                        isPinch = false;
 | 
			
		||||
                        isPan = true;
 | 
			
		||||
 | 
			
		||||
                        // Position of single touch is tracked and
 | 
			
		||||
                        // saved in variable
 | 
			
		||||
                        touchPosition = trackPosition(event.touches[0]);
 | 
			
		||||
 | 
			
		||||
                        // Emits the start of the pan and passes the
 | 
			
		||||
                        // touch coordinates (touch), and the bounds
 | 
			
		||||
                        // of the event
 | 
			
		||||
                        $scope.$emit('mct:pan:start', {
 | 
			
		||||
                            touch: touchPosition,
 | 
			
		||||
                            bounds: event.target.getBoundingClientRect()
 | 
			
		||||
                        });
 | 
			
		||||
                        
 | 
			
		||||
                        // Stops other gestures/button clicks from being active
 | 
			
		||||
                        event.preventDefault();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // As the touch move occurs, the touches are tracked and
 | 
			
		||||
                // the event is emitted through scope
 | 
			
		||||
                function touchChange(event) {
 | 
			
		||||
                    var touchPosition;
 | 
			
		||||
 | 
			
		||||
                    // If two touches or change touches are occurring
 | 
			
		||||
                    // and the user has started a pinch than user is
 | 
			
		||||
                    // doing a pinch gesture
 | 
			
		||||
                    if (checkPinch(event) && isPinch) {
 | 
			
		||||
 | 
			
		||||
                        // Position of both touches are tracked and saved in variable. If change
 | 
			
		||||
                        // in touch of either coordinate is undefined, uses touch instead
 | 
			
		||||
                        touchPosition = [trackPosition(event.changedTouches[0] || event.touches[0]),
 | 
			
		||||
                            trackPosition(event.changedTouches[1] || event.touches[1])];
 | 
			
		||||
 | 
			
		||||
                        // Emits the change in pinch and passes the
 | 
			
		||||
                        // touch coordinates (touches), the bounds of the
 | 
			
		||||
                        // event, the midpoint of both touch coorddinates,
 | 
			
		||||
                        // and the distance between the two touch coordinates
 | 
			
		||||
                        $scope.$emit('mct:pinch:change', {
 | 
			
		||||
                            touches: touchPosition,
 | 
			
		||||
                            bounds: event.target.getBoundingClientRect(),
 | 
			
		||||
                            midpoint: calculateMidpoint(touchPosition[0], touchPosition[1]),
 | 
			
		||||
                            distance: calculateDistance(touchPosition[0], touchPosition[1])
 | 
			
		||||
                        });
 | 
			
		||||
                        
 | 
			
		||||
                        // Stops other gestures/button clicks from being active
 | 
			
		||||
                        event.preventDefault();
 | 
			
		||||
                    }
 | 
			
		||||
                    // If one touch or change touch is occurring
 | 
			
		||||
                    // user is doing a single finger pan gesture
 | 
			
		||||
                    else if (checkPan(event) && isPan) {
 | 
			
		||||
 | 
			
		||||
                        // Position of single changed touch or touch is tracked and saved in variable
 | 
			
		||||
                        touchPosition = trackPosition(event.changedTouches[0] || event.touches[0]);
 | 
			
		||||
 | 
			
		||||
                        // Emits the change of the pan and passes the
 | 
			
		||||
                        // touch coordinates (touch), and the bounds
 | 
			
		||||
                        // of the event
 | 
			
		||||
                        $scope.$emit('mct:pan:change', {
 | 
			
		||||
                            touch: touchPosition,
 | 
			
		||||
                            bounds: event.target.getBoundingClientRect()
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        // Stops other gestures/button clicks from being active
 | 
			
		||||
                        event.preventDefault();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // On the 'touchend' or 'touchcancel' the event
 | 
			
		||||
                // is emitted through scope
 | 
			
		||||
                function touchEnd(event) {
 | 
			
		||||
 | 
			
		||||
                    // Emits that this is the end of the touch
 | 
			
		||||
                    $scope.$emit('mct:ptouch:end');
 | 
			
		||||
 | 
			
		||||
                    // set pan/pinch statuses to false
 | 
			
		||||
                    // when the user stops touching the screen
 | 
			
		||||
                    isPan = false;
 | 
			
		||||
                    isPinch = false;
 | 
			
		||||
 | 
			
		||||
                    // Stops other gestures/button clicks from being active
 | 
			
		||||
                    event.preventDefault();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // On Mobile, checks for touch start, move, and end/cancel
 | 
			
		||||
                if (agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                    element.on('touchstart', touchStart);
 | 
			
		||||
                    element.on('touchmove', touchChange);
 | 
			
		||||
                    element.on('touchend', touchEnd);
 | 
			
		||||
                    element.on('touchcancel', touchEnd);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Stop checking for touch when scope is destroyed
 | 
			
		||||
                // (when user navigates away from graph).
 | 
			
		||||
                $scope.$on("$destroy", function () {
 | 
			
		||||
 | 
			
		||||
                    // All elements' event listeners are
 | 
			
		||||
                    // removed
 | 
			
		||||
                    element.off('touchstart', touchStart);
 | 
			
		||||
                    element.off('touchmove', touchChange);
 | 
			
		||||
                    element.off('touchend', touchEnd);
 | 
			
		||||
                    element.off('touchcancel', touchEnd);
 | 
			
		||||
 | 
			
		||||
                    // If for some reason, midtouch the
 | 
			
		||||
                    // user is navigated away, set pan/pinch
 | 
			
		||||
                    // statuses to false
 | 
			
		||||
                    isPan = false;
 | 
			
		||||
                    isPinch = false;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                // MCTPinch is treated as an attribute
 | 
			
		||||
                restrict: "A",
 | 
			
		||||
 | 
			
		||||
                // Link with the provided function above
 | 
			
		||||
                link: link
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return MCTPinch;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										465
									
								
								platform/features/plot-reborn/src/directives/MCTPlot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								platform/features/plot-reborn/src/directives/MCTPlot.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,465 @@
 | 
			
		||||
/*global define,window*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        '../lib/utils'
 | 
			
		||||
    ],
 | 
			
		||||
    function (utils) {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        var RANGE_TICK_COUNT = 7,
 | 
			
		||||
            DOMAIN_TICK_COUNT = 5,
 | 
			
		||||
            ZOOM_AMT = 0.02,
 | 
			
		||||
            PINCH_DRAG_AMT = 3;
 | 
			
		||||
 | 
			
		||||
        function MCTPlot() {
 | 
			
		||||
 | 
			
		||||
            function link($scope, $element) {
 | 
			
		||||
                // Now that we're here, let's handle some scope management that the controller would otherwise handle.
 | 
			
		||||
 | 
			
		||||
                if (typeof $scope.rectangles === "undefined") {
 | 
			
		||||
                    $scope.rectangles = [];
 | 
			
		||||
                }
 | 
			
		||||
                if (typeof $scope.displayableRange === "undefined") {
 | 
			
		||||
                    $scope.displayableRange = function (x) { return x; };
 | 
			
		||||
                }
 | 
			
		||||
                if (typeof $scope.displayableDomain === "undefined") {
 | 
			
		||||
                    $scope.displayableDomain = function (x) { return x; };
 | 
			
		||||
                }
 | 
			
		||||
                if (typeof $scope.axes === "undefined") {
 | 
			
		||||
                    $scope.axes = {
 | 
			
		||||
                        domain: {
 | 
			
		||||
                            label: "Time (Updating Live)",
 | 
			
		||||
                            tickCount: DOMAIN_TICK_COUNT,
 | 
			
		||||
                            ticks: []
 | 
			
		||||
                        },
 | 
			
		||||
                        range: {
 | 
			
		||||
                            label: "Value",
 | 
			
		||||
                            tickCount: RANGE_TICK_COUNT,
 | 
			
		||||
                            ticks: []
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var dragStart,
 | 
			
		||||
                    marqueeBox = {},
 | 
			
		||||
                    marqueeRect, // Set when exists.
 | 
			
		||||
                    chartElementBounds,
 | 
			
		||||
                    firstTouch,
 | 
			
		||||
                    firstTouchDistance,
 | 
			
		||||
                    prevTouchDistance,
 | 
			
		||||
                    $canvas = $element.find('canvas');
 | 
			
		||||
 | 
			
		||||
                function updateAxesForCurrentViewport() {
 | 
			
		||||
                    // Update axes definitions for current viewport.
 | 
			
		||||
                    ['domain', 'range'].forEach(function (axisName) {
 | 
			
		||||
                        var axis = $scope.axes[axisName],
 | 
			
		||||
                            firstTick = $scope.viewport.topLeft[axisName],
 | 
			
		||||
                            lastTick = $scope.viewport.bottomRight[axisName],
 | 
			
		||||
                            axisSize = firstTick - lastTick,
 | 
			
		||||
                            denominator = axis.tickCount - 1,
 | 
			
		||||
                            tickNumber,
 | 
			
		||||
                            tickIncrement,
 | 
			
		||||
                            tickValue;
 | 
			
		||||
                        // Yes, ticksize is negative for domain and positive for range.
 | 
			
		||||
                        // It's because ticks are generated/displayed top to bottom and left to right.
 | 
			
		||||
                        axis.ticks = [];
 | 
			
		||||
                        for (tickNumber = 0; tickNumber < axis.tickCount; tickNumber = tickNumber + 1) {
 | 
			
		||||
                            tickIncrement = (axisSize * (tickNumber / denominator));
 | 
			
		||||
                            tickValue = firstTick - tickIncrement;
 | 
			
		||||
                            axis.ticks.push(
 | 
			
		||||
                                tickValue
 | 
			
		||||
                            );
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function drawMarquee() {
 | 
			
		||||
                    // Create rectangle for Marquee if it should be set.
 | 
			
		||||
                    if (marqueeBox && marqueeBox.start && marqueeBox.end) {
 | 
			
		||||
                        if (!marqueeRect) {
 | 
			
		||||
                            marqueeRect = {};
 | 
			
		||||
                            $scope.rectangles.push(marqueeRect);
 | 
			
		||||
                        }
 | 
			
		||||
                        marqueeRect.start = marqueeBox.start;
 | 
			
		||||
                        marqueeRect.end = marqueeBox.end;
 | 
			
		||||
                        marqueeRect.color = [1, 1, 1, 0.5];
 | 
			
		||||
                        marqueeRect.layer = 'top'; // TODO: implement this.
 | 
			
		||||
                        $scope.$broadcast('rectangle-change');
 | 
			
		||||
                    } else if (marqueeRect && $scope.rectangles.indexOf(marqueeRect) !== -1) {
 | 
			
		||||
                        $scope.rectangles.splice($scope.rectangles.indexOf(marqueeRect));
 | 
			
		||||
                        marqueeRect = undefined;
 | 
			
		||||
                        $scope.$broadcast('rectangle-change');
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function untrackMousePosition() {
 | 
			
		||||
                    $scope.mouseCoordinates = undefined;
 | 
			
		||||
                }
 | 
			
		||||
                function updateMarquee() {
 | 
			
		||||
                    // Update the marquee box in progress.
 | 
			
		||||
                    marqueeBox.end = $scope.mouseCoordinates.positionAsPlotPoint;
 | 
			
		||||
                    drawMarquee();
 | 
			
		||||
                }
 | 
			
		||||
                function startMarquee() {
 | 
			
		||||
                    marqueeBox.start = $scope.mouseCoordinates.positionAsPlotPoint;
 | 
			
		||||
                }
 | 
			
		||||
                function endMarquee() {
 | 
			
		||||
                    // marqueeBox start/end are opposite corners but we need
 | 
			
		||||
                    // topLeft and bottomRight.
 | 
			
		||||
                    var boxPoints = utils.boxPointsFromOppositeCorners(marqueeBox.start, marqueeBox.end),
 | 
			
		||||
                        newViewport = utils.oppositeCornersFromBoxPoints(boxPoints);
 | 
			
		||||
 | 
			
		||||
                    marqueeBox = {};
 | 
			
		||||
                    drawMarquee();
 | 
			
		||||
                    $scope.$emit('user:viewport:change:end', newViewport);
 | 
			
		||||
                    $scope.viewport = newViewport;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function startDrag($event) {
 | 
			
		||||
                    $scope.$emit('user:viewport:change:start');
 | 
			
		||||
                    if (!$scope.mouseCoordinates) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    $event.preventDefault();
 | 
			
		||||
                    // Track drag location relative to position over element
 | 
			
		||||
                    // not domain, as chart viewport will change as we drag.
 | 
			
		||||
                    dragStart = $scope.mouseCoordinates.positionAsPlotPoint;
 | 
			
		||||
                    // Tell controller that we're starting to navigate.
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function updateDrag() {
 | 
			
		||||
                    // calculate offset between points.  Apply that offset to viewport.
 | 
			
		||||
                    var newPosition = $scope.mouseCoordinates.positionAsPlotPoint,
 | 
			
		||||
                        dDomain = dragStart.domain - newPosition.domain,
 | 
			
		||||
                        dRange = dragStart.range - newPosition.range;
 | 
			
		||||
 | 
			
		||||
                    $scope.viewport = {
 | 
			
		||||
                        topLeft: {
 | 
			
		||||
                            domain: $scope.viewport.topLeft.domain + dDomain,
 | 
			
		||||
                            range: $scope.viewport.topLeft.range + dRange
 | 
			
		||||
                        },
 | 
			
		||||
                        bottomRight: {
 | 
			
		||||
                            domain: $scope.viewport.bottomRight.domain + dDomain,
 | 
			
		||||
                            range: $scope.viewport.bottomRight.range + dRange
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function endDrag() {
 | 
			
		||||
                    dragStart = undefined;
 | 
			
		||||
                    $scope.$emit('user:viewport:change:end', $scope.viewport);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Similar to trackMousePosition, where the touch position is converted
 | 
			
		||||
                // into a plot point position and over element position using utils
 | 
			
		||||
                function trackTouchPosition(touchPosition, bounds) {
 | 
			
		||||
                    var positionOverElement,
 | 
			
		||||
                        positionAsPlotPoint,
 | 
			
		||||
                        position;
 | 
			
		||||
                    
 | 
			
		||||
                    chartElementBounds = bounds;
 | 
			
		||||
                    
 | 
			
		||||
                    positionOverElement = {
 | 
			
		||||
                        x: touchPosition.clientX - bounds.left,
 | 
			
		||||
                        y: touchPosition.clientY - bounds.top
 | 
			
		||||
                    };
 | 
			
		||||
                    
 | 
			
		||||
                    positionAsPlotPoint = utils.elementPositionAsPlotPosition(
 | 
			
		||||
                        positionOverElement,
 | 
			
		||||
                        bounds,
 | 
			
		||||
                        $scope.viewport
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    position = {
 | 
			
		||||
                        positionOverElement: positionOverElement,
 | 
			
		||||
                        positionAsPlotPoint: positionAsPlotPoint
 | 
			
		||||
                    };
 | 
			
		||||
                    
 | 
			
		||||
                    return position;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function trackMousePosition($event) {
 | 
			
		||||
                    // Calculate coordinates of mouse related to canvas and as
 | 
			
		||||
                    // domain, range value and make available in scope for display.
 | 
			
		||||
 | 
			
		||||
                    var bounds = $event.target.getBoundingClientRect(),
 | 
			
		||||
                        positionOverElement,
 | 
			
		||||
                        positionAsPlotPoint;
 | 
			
		||||
 | 
			
		||||
                    chartElementBounds = bounds;
 | 
			
		||||
 | 
			
		||||
                    
 | 
			
		||||
                    positionOverElement = {
 | 
			
		||||
                        x: $event.clientX - bounds.left,
 | 
			
		||||
                        y: $event.clientY - bounds.top
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    positionAsPlotPoint = utils.elementPositionAsPlotPosition(
 | 
			
		||||
                        positionOverElement,
 | 
			
		||||
                        bounds,
 | 
			
		||||
                        $scope.viewport
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    $scope.mouseCoordinates = {
 | 
			
		||||
                        positionOverElement: positionOverElement,
 | 
			
		||||
                        positionAsPlotPoint: positionAsPlotPoint
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    if (marqueeBox && marqueeBox.start) {
 | 
			
		||||
                        updateMarquee();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (dragStart) {
 | 
			
		||||
                        updateDrag();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function watchForMarquee() {
 | 
			
		||||
                    $canvas.removeClass('plot-drag');
 | 
			
		||||
                    $canvas.addClass('plot-marquee');
 | 
			
		||||
                    $canvas.on('mousedown', startMarquee);
 | 
			
		||||
                    $canvas.on('mouseup', endMarquee);
 | 
			
		||||
                    $canvas.off('mousedown', startDrag);
 | 
			
		||||
                    $canvas.off('mouseup', endDrag);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function watchForDrag() {
 | 
			
		||||
                    $canvas.addClass('plot-drag');
 | 
			
		||||
                    $canvas.removeClass('plot-marquee');
 | 
			
		||||
                    $canvas.on('mousedown', startDrag);
 | 
			
		||||
                    $canvas.on('mouseup', endDrag);
 | 
			
		||||
                    $canvas.off('mousedown', startMarquee);
 | 
			
		||||
                    $canvas.off('mouseup', endMarquee);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function toggleInteractionMode(event) {
 | 
			
		||||
                    if (event.keyCode === 16) { // shift key.
 | 
			
		||||
                        watchForDrag();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function resetInteractionMode(event) {
 | 
			
		||||
                    if (event.keyCode === 16) {
 | 
			
		||||
                        watchForMarquee();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function stopWatching() {
 | 
			
		||||
                    $canvas.off('mousedown', startDrag);
 | 
			
		||||
                    $canvas.off('mouseup', endDrag);
 | 
			
		||||
                    $canvas.off('mousedown', startMarquee);
 | 
			
		||||
                    $canvas.off('mouseup', endMarquee);
 | 
			
		||||
                    window.removeEventListener('keydown', toggleInteractionMode);
 | 
			
		||||
                    window.removeEventListener('keyup', resetInteractionMode);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $canvas.on('mousemove', trackMousePosition);
 | 
			
		||||
                $canvas.on('mouseleave', untrackMousePosition);
 | 
			
		||||
                watchForMarquee();
 | 
			
		||||
 | 
			
		||||
                window.addEventListener('keydown', toggleInteractionMode);
 | 
			
		||||
                window.addEventListener('keyup', resetInteractionMode);
 | 
			
		||||
 | 
			
		||||
                function onViewportChange() {
 | 
			
		||||
                    if ($scope.mouseCoordinates && chartElementBounds) {
 | 
			
		||||
                        $scope.mouseCoordinates.positionAsPlotPoint =
 | 
			
		||||
                            utils.elementPositionAsPlotPosition(
 | 
			
		||||
                                $scope.mouseCoordinates.positionOverElement,
 | 
			
		||||
                                chartElementBounds,
 | 
			
		||||
                                $scope.viewport
 | 
			
		||||
                            );
 | 
			
		||||
                    }
 | 
			
		||||
                    // TODO: Discuss whether marqueeBox start should be fixed to data or fixed to canvas element, especially when "isLive is true".
 | 
			
		||||
                    updateAxesForCurrentViewport();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Updates viewport based on touch location and current event bounds
 | 
			
		||||
                function updatePan(touch, bounds) {
 | 
			
		||||
 | 
			
		||||
                    // Sets the panPosition plot point (relative to chart)
 | 
			
		||||
                    // and calculates domain/range by subtracting first touch's
 | 
			
		||||
                    // plot point and current touch's plot point
 | 
			
		||||
                    var panPosition = trackTouchPosition(touch, bounds).positionAsPlotPoint,
 | 
			
		||||
                        dDomain = firstTouch.domain - panPosition.domain,
 | 
			
		||||
                        dRange = firstTouch.range - panPosition.range;
 | 
			
		||||
 | 
			
		||||
                    // Viewport is set to calculated delta domain/range
 | 
			
		||||
                    $scope.viewport = {
 | 
			
		||||
                        topLeft: {
 | 
			
		||||
                            domain: (($scope.viewport.topLeft.domain) + dDomain),
 | 
			
		||||
                            range: (($scope.viewport.topLeft.range) + dRange)
 | 
			
		||||
                        },
 | 
			
		||||
                        bottomRight: {
 | 
			
		||||
                            domain: (($scope.viewport.bottomRight.domain) + dDomain),
 | 
			
		||||
                            range: (($scope.viewport.bottomRight.range) + dRange)
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Starts the pan by emitting that viewport will be changed
 | 
			
		||||
                // also sets the first touch variable
 | 
			
		||||
                function startPan(touch, bounds) {
 | 
			
		||||
                    $scope.$emit('user:viewport:change:start');
 | 
			
		||||
                    firstTouch = trackTouchPosition(touch, bounds).positionAsPlotPoint;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Receives the emit of single touch pan start
 | 
			
		||||
                function onPanStart(event, touch) {
 | 
			
		||||
                    startPan(touch.touch, touch.bounds);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Receives the emit of single touch pan change
 | 
			
		||||
                function onPanChange(event, touch) {
 | 
			
		||||
                    updatePan(touch.touch, touch.bounds);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Sets the dimensions of the midpoint's domain and range distance to the
 | 
			
		||||
                // top left and bottom right corners of the viewport. Used to zoom relative to
 | 
			
		||||
                // midpoint pinch gestures 2 touches.
 | 
			
		||||
                function setDimensions(midpoint) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        tl: {
 | 
			
		||||
                            domain: Math.abs(midpoint.domain - ($scope.viewport.topLeft.domain)),
 | 
			
		||||
                            range: Math.abs(midpoint.range - ($scope.viewport.topLeft.range))
 | 
			
		||||
                        },
 | 
			
		||||
                        br: {
 | 
			
		||||
                            domain: Math.abs(($scope.viewport.bottomRight.domain) - midpoint.domain),
 | 
			
		||||
                            range: Math.abs(($scope.viewport.bottomRight.range) - midpoint.range)
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Calculates the viewport for a zoom gesture
 | 
			
		||||
                function calculateViewport(midpoint, ratio) {
 | 
			
		||||
 | 
			
		||||
                    // Uses the distance ratio passed in and the
 | 
			
		||||
                    // zoom amount (variable set at top) to find the
 | 
			
		||||
                    // amount of zoom per change in pinch gesture and
 | 
			
		||||
                    // whether it is zooming in or out
 | 
			
		||||
                    var zoomTL, zoomBR,
 | 
			
		||||
                        dimensions = setDimensions(midpoint),
 | 
			
		||||
                        checkRatio = (ratio - 1) || 0,
 | 
			
		||||
                        type = (-1 * (checkRatio / Math.abs(checkRatio))) || 1,
 | 
			
		||||
                        zoomAmt = type * ZOOM_AMT;
 | 
			
		||||
 | 
			
		||||
                    // Sets the domain/range difference to applied to the
 | 
			
		||||
                    // top left and bottom right plot points
 | 
			
		||||
                    zoomTL = {
 | 
			
		||||
                        domain: zoomAmt * dimensions.tl.domain,
 | 
			
		||||
                        range: zoomAmt * dimensions.tl.range
 | 
			
		||||
                    };
 | 
			
		||||
                    zoomBR = {
 | 
			
		||||
                        domain: zoomAmt * dimensions.br.domain,
 | 
			
		||||
                        range: zoomAmt * dimensions.br.range
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    // Applies and returns the changed for zoom top left and bottom right
 | 
			
		||||
                    // plot points
 | 
			
		||||
                    return {
 | 
			
		||||
                        topLeft: {
 | 
			
		||||
                            domain: (($scope.viewport.topLeft.domain) + zoomTL.domain),
 | 
			
		||||
                            range: (($scope.viewport.topLeft.range) - zoomTL.range)
 | 
			
		||||
                        },
 | 
			
		||||
                        bottomRight: {
 | 
			
		||||
                            domain: (($scope.viewport.bottomRight.domain) - zoomBR.domain),
 | 
			
		||||
                            range: (($scope.viewport.bottomRight.range) + zoomBR.range)
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Updates the viewport based on the amount of zooming (pinching) user is doing
 | 
			
		||||
                // Pinch inwards (zoom out): distanceRatio > 1
 | 
			
		||||
                // Pinch outwards (zoom in): distanceRatio < 1
 | 
			
		||||
                function updateZoom(midpoint, bounds, distance) {
 | 
			
		||||
 | 
			
		||||
                    // Gets the current midpoint and distance ratio to be used to
 | 
			
		||||
                    // calculate new viewport
 | 
			
		||||
                    var midpointPosition = trackTouchPosition(midpoint, bounds).positionAsPlotPoint,
 | 
			
		||||
                        distanceRatio = ((prevTouchDistance || firstTouchDistance) / distance);
 | 
			
		||||
 | 
			
		||||
                    // Sets the new viewport
 | 
			
		||||
                    $scope.viewport = calculateViewport(midpointPosition, distanceRatio);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Starts the zoom by emitting that viewport will be changed
 | 
			
		||||
                // also sets the first touch variable (midpoint) if panning will
 | 
			
		||||
                // happen and sets the distance between the first touches occurring
 | 
			
		||||
                function startZoom(midpoint, bounds, distance) {
 | 
			
		||||
                    $scope.$emit('user:viewport:change:start');
 | 
			
		||||
                    firstTouchDistance = distance;
 | 
			
		||||
                    firstTouch = trackTouchPosition(midpoint, bounds).positionAsPlotPoint;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Receives the emit of the start of pinch touch
 | 
			
		||||
                function onPinchStart(event, touch) {
 | 
			
		||||
                    startZoom(touch.midpoint, touch.bounds, touch.distance);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function comparePinchDrag(distance, prevDistance) {
 | 
			
		||||
                    return ((prevDistance + PINCH_DRAG_AMT) >= distance) &&
 | 
			
		||||
                        ((prevDistance - PINCH_DRAG_AMT) <= distance);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Receives the emit of the change of pinch touch,
 | 
			
		||||
                // differentiates between a pan and zoom
 | 
			
		||||
                function onPinchChange(event, touch) {
 | 
			
		||||
 | 
			
		||||
                    // Will pan if change in distance is within PINCH_DRAG_AMT
 | 
			
		||||
                    // range relative to the previous distance
 | 
			
		||||
                    if(comparePinchDrag(Math.round(touch.distance),
 | 
			
		||||
                            Math.round(prevTouchDistance || firstTouchDistance))) {
 | 
			
		||||
                        updatePan(touch.midpoint, touch.bounds);
 | 
			
		||||
                    }
 | 
			
		||||
                    // Will pinch in any other situation that the distance between
 | 
			
		||||
                    // pinching touches is increasing or decreasing by more than
 | 
			
		||||
                    // PINCH_DRAG_AMT
 | 
			
		||||
                    else {
 | 
			
		||||
                        updateZoom(touch.midpoint, touch.bounds, touch.distance);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Sets previous touch distance to current touch.distance (for next touch event)
 | 
			
		||||
                    prevTouchDistance = touch.distance;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Receives emit for touch event ending and emits that the
 | 
			
		||||
                // viewport has stopped changing.
 | 
			
		||||
                function onTouchEnd() {
 | 
			
		||||
                    $scope.$emit('user:viewport:change:end', $scope.viewport);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Receives the pinch to allow pinching/panning emitted by MCTPinch
 | 
			
		||||
                $scope.$on('mct:pinch:start', onPinchStart);
 | 
			
		||||
                $scope.$on('mct:pinch:change', onPinchChange);
 | 
			
		||||
 | 
			
		||||
                // Receives the pan to allow panning emitted by MCTPinch
 | 
			
		||||
                $scope.$on('mct:pan:start', onPanStart);
 | 
			
		||||
                $scope.$on('mct:pan:change', onPanChange);
 | 
			
		||||
 | 
			
		||||
                // Receives the end of the pan/pinch emitted by MCTPinch
 | 
			
		||||
                $scope.$on('mct:ptouch:end', onTouchEnd);
 | 
			
		||||
 | 
			
		||||
                $scope.$on('$destroy', stopWatching);
 | 
			
		||||
 | 
			
		||||
                $scope.$watchCollection('viewport', onViewportChange);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                restrict: "E",
 | 
			
		||||
                templateUrl: 'platform/features/plot-reborn/res/templates/mct-plot.html',
 | 
			
		||||
                link: link,
 | 
			
		||||
                scope: {
 | 
			
		||||
                    viewport: "=",
 | 
			
		||||
                    series: "=",
 | 
			
		||||
                    rectangles: "=?",
 | 
			
		||||
                    axes: "=?",
 | 
			
		||||
                    displayableRange: "=?",
 | 
			
		||||
                    displayableDomain: "=?"
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return MCTPlot;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										120
									
								
								platform/features/plot-reborn/src/draw/Draw2D.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								platform/features/plot-reborn/src/draw/Draw2D.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Create a new draw API utilizing the Canvas's 2D API for rendering.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {CanvasElement} canvas the canvas object to render upon
 | 
			
		||||
         * @throws {Error} an error is thrown if Canvas's 2D API is unavailable.
 | 
			
		||||
         */
 | 
			
		||||
        function Draw2D(canvas) {
 | 
			
		||||
            var c2d = canvas.getContext('2d'),
 | 
			
		||||
                width = canvas.width,
 | 
			
		||||
                height = canvas.height,
 | 
			
		||||
                dimensions = [ width, height ],
 | 
			
		||||
                origin = [ 0, 0 ];
 | 
			
		||||
 | 
			
		||||
            // Convert from logical to physical x coordinates
 | 
			
		||||
            function x(v) {
 | 
			
		||||
                return ((v - origin[0]) / dimensions[0]) * width;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Convert from logical to physical y coordinates
 | 
			
		||||
            function y(v) {
 | 
			
		||||
                return height - ((v - origin[1]) / dimensions[1]) * height;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Set the color to be used for drawing operations
 | 
			
		||||
            function setColor(color) {
 | 
			
		||||
                var mappedColor = color.map(function (c, i) {
 | 
			
		||||
                        return i < 3 ? Math.floor(c * 255) : (c);
 | 
			
		||||
                    }).join(',');
 | 
			
		||||
                c2d.strokeStyle = "rgba(" + mappedColor + ")";
 | 
			
		||||
                c2d.fillStyle = "rgba(" + mappedColor + ")";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!c2d) {
 | 
			
		||||
                throw new Error("Canvas 2d API unavailable.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                /**
 | 
			
		||||
                 * Clear the chart.
 | 
			
		||||
                 */
 | 
			
		||||
                clear: function () {
 | 
			
		||||
                    width = canvas.width;
 | 
			
		||||
                    height = canvas.height;
 | 
			
		||||
                    c2d.clearRect(0, 0, width, height);
 | 
			
		||||
                },
 | 
			
		||||
                /**
 | 
			
		||||
                 * Set the logical boundaries of the chart.
 | 
			
		||||
                 * @param {number[]} dimensions the horizontal and
 | 
			
		||||
                 *        vertical dimensions of the chart
 | 
			
		||||
                 * @param {number[]} origin the horizontal/vertical
 | 
			
		||||
                 *        origin of the chart
 | 
			
		||||
                 */
 | 
			
		||||
                setDimensions: function (newDimensions, newOrigin) {
 | 
			
		||||
                    dimensions = newDimensions;
 | 
			
		||||
                    origin = newOrigin;
 | 
			
		||||
                },
 | 
			
		||||
                /**
 | 
			
		||||
                 * Draw the supplied buffer as a line strip (a sequence
 | 
			
		||||
                 * of line segments), in the chosen color.
 | 
			
		||||
                 * @param {Float32Array} buf the line strip to draw,
 | 
			
		||||
                 *        in alternating x/y positions
 | 
			
		||||
                 * @param {number[]} color the color to use when drawing
 | 
			
		||||
                 *        the line, as an RGBA color where each element
 | 
			
		||||
                 *        is in the range of 0.0-1.0
 | 
			
		||||
                 * @param {number} points the number of points to draw
 | 
			
		||||
                 */
 | 
			
		||||
                drawLine: function (buf, color, points) {
 | 
			
		||||
                    var i;
 | 
			
		||||
 | 
			
		||||
                    setColor(color);
 | 
			
		||||
 | 
			
		||||
                    // Configure context to draw two-pixel-thick lines
 | 
			
		||||
                    c2d.lineWidth = 2;
 | 
			
		||||
 | 
			
		||||
                    // Start a new path...
 | 
			
		||||
                    if (buf.length > 1) {
 | 
			
		||||
                        c2d.beginPath();
 | 
			
		||||
                        c2d.moveTo(x(buf[0]), y(buf[1]));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // ...and add points to it...
 | 
			
		||||
                    for (i = 2; i < points * 2; i = i + 2) {
 | 
			
		||||
                        c2d.lineTo(x(buf[i]), y(buf[i + 1]));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // ...before finally drawing it.
 | 
			
		||||
                    c2d.stroke();
 | 
			
		||||
                },
 | 
			
		||||
                /**
 | 
			
		||||
                 * Draw a rectangle extending from one corner to another,
 | 
			
		||||
                 * in the chosen color.
 | 
			
		||||
                 * @param {number[]} min the first corner of the rectangle
 | 
			
		||||
                 * @param {number[]} max the opposite corner
 | 
			
		||||
                 * @param {number[]} color the color to use when drawing
 | 
			
		||||
                 *        the rectangle, as an RGBA color where each element
 | 
			
		||||
                 *        is in the range of 0.0-1.0
 | 
			
		||||
                 */
 | 
			
		||||
                drawSquare: function (min, max, color) {
 | 
			
		||||
                    var x1 = x(min[0]),
 | 
			
		||||
                        y1 = y(min[1]),
 | 
			
		||||
                        w = x(max[0]) - x1,
 | 
			
		||||
                        h = y(max[1]) - y1;
 | 
			
		||||
 | 
			
		||||
                    setColor(color);
 | 
			
		||||
                    c2d.fillRect(x1, y1, w, h);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Draw2D;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										46
									
								
								platform/features/plot-reborn/src/draw/DrawLoader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								platform/features/plot-reborn/src/draw/DrawLoader.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/*global define,$log */
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        './DrawWebGL',
 | 
			
		||||
        './Draw2D'
 | 
			
		||||
    ],
 | 
			
		||||
    function ($log, DrawWebGL, Draw2D) {
 | 
			
		||||
 | 
			
		||||
        var CHARTS = [
 | 
			
		||||
            DrawWebGL,
 | 
			
		||||
            Draw2D
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Draw loader attaches a draw API to a canvas element and returns the
 | 
			
		||||
         * draw API.
 | 
			
		||||
         */
 | 
			
		||||
        return {
 | 
			
		||||
            /**
 | 
			
		||||
             * Return the first draw API available.  Returns
 | 
			
		||||
             * `undefined` if a draw API could not be constructed.
 | 
			
		||||
             *.
 | 
			
		||||
             * @param {CanvasElement} canvas - The canvas eelement to attach
 | 
			
		||||
                      the draw API to.
 | 
			
		||||
             */
 | 
			
		||||
            getDrawAPI: function (canvas) {
 | 
			
		||||
                var i;
 | 
			
		||||
                for (i = 0; i < CHARTS.length; i++) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        return new CHARTS[i](canvas);
 | 
			
		||||
                    } catch (e) {
 | 
			
		||||
                        $log.warn([
 | 
			
		||||
                            "Could not instantiate chart",
 | 
			
		||||
                            CHARTS[i].name,
 | 
			
		||||
                            ";",
 | 
			
		||||
                            e.message
 | 
			
		||||
                        ].join(" "));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                $log.warn("Cannot initialize mct-chart.");
 | 
			
		||||
                return undefined;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										152
									
								
								platform/features/plot-reborn/src/draw/DrawWebGL.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								platform/features/plot-reborn/src/draw/DrawWebGL.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
/*global define,Float32Array*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        // WebGL shader sources (for drawing plain colors)
 | 
			
		||||
        var FRAGMENT_SHADER = [
 | 
			
		||||
                "precision mediump float;",
 | 
			
		||||
                "uniform vec4 uColor;",
 | 
			
		||||
                "void main(void) {",
 | 
			
		||||
                "gl_FragColor = uColor;",
 | 
			
		||||
                "}"
 | 
			
		||||
            ].join('\n'),
 | 
			
		||||
            VERTEX_SHADER = [
 | 
			
		||||
                "attribute vec2 aVertexPosition;",
 | 
			
		||||
                "uniform vec2 uDimensions;",
 | 
			
		||||
                "uniform vec2 uOrigin;",
 | 
			
		||||
                "void main(void) {",
 | 
			
		||||
                "gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);",
 | 
			
		||||
                "}"
 | 
			
		||||
            ].join('\n');
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Create a draw api utilizing WebGL.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {CanvasElement} canvas the canvas object to render upon
 | 
			
		||||
         * @throws {Error} an error is thrown if WebGL is unavailable.
 | 
			
		||||
         */
 | 
			
		||||
        function DrawWebGL(canvas) {
 | 
			
		||||
            var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"),
 | 
			
		||||
                vertexShader,
 | 
			
		||||
                fragmentShader,
 | 
			
		||||
                program,
 | 
			
		||||
                aVertexPosition,
 | 
			
		||||
                uColor,
 | 
			
		||||
                uDimensions,
 | 
			
		||||
                uOrigin,
 | 
			
		||||
                buffer;
 | 
			
		||||
 | 
			
		||||
            // Ensure a context was actually available before proceeding
 | 
			
		||||
            if (!gl) {
 | 
			
		||||
                throw new Error("WebGL unavailable.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Initialize shaders
 | 
			
		||||
            vertexShader = gl.createShader(gl.VERTEX_SHADER);
 | 
			
		||||
            gl.shaderSource(vertexShader, VERTEX_SHADER);
 | 
			
		||||
            gl.compileShader(vertexShader);
 | 
			
		||||
            fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
 | 
			
		||||
            gl.shaderSource(fragmentShader, FRAGMENT_SHADER);
 | 
			
		||||
            gl.compileShader(fragmentShader);
 | 
			
		||||
 | 
			
		||||
            // Assemble vertex/fragment shaders into programs
 | 
			
		||||
            program = gl.createProgram();
 | 
			
		||||
            gl.attachShader(program, vertexShader);
 | 
			
		||||
            gl.attachShader(program, fragmentShader);
 | 
			
		||||
            gl.linkProgram(program);
 | 
			
		||||
            gl.useProgram(program);
 | 
			
		||||
 | 
			
		||||
            // Get locations for attribs/uniforms from the
 | 
			
		||||
            // shader programs (to pass values into shaders at draw-time)
 | 
			
		||||
            aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
 | 
			
		||||
            uColor = gl.getUniformLocation(program, "uColor");
 | 
			
		||||
            uDimensions = gl.getUniformLocation(program, "uDimensions");
 | 
			
		||||
            uOrigin = gl.getUniformLocation(program, "uOrigin");
 | 
			
		||||
            gl.enableVertexAttribArray(aVertexPosition);
 | 
			
		||||
 | 
			
		||||
            // Create a buffer to holds points which will be drawn
 | 
			
		||||
            buffer = gl.createBuffer();
 | 
			
		||||
 | 
			
		||||
            // Use a line width of 2.0 for legibility
 | 
			
		||||
            gl.lineWidth(2.0);
 | 
			
		||||
 | 
			
		||||
            // Enable blending, for smoothness
 | 
			
		||||
            gl.enable(gl.BLEND);
 | 
			
		||||
            gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
 | 
			
		||||
 | 
			
		||||
            // Utility function to handle drawing of a buffer;
 | 
			
		||||
            // drawType will determine whether this is a box, line, etc.
 | 
			
		||||
            function doDraw(drawType, buf, color, points) {
 | 
			
		||||
                gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
 | 
			
		||||
                gl.bufferData(gl.ARRAY_BUFFER, buf, gl.DYNAMIC_DRAW);
 | 
			
		||||
                gl.vertexAttribPointer(aVertexPosition, 2, gl.FLOAT, false, 0, 0);
 | 
			
		||||
                gl.uniform4fv(uColor, color);
 | 
			
		||||
                gl.drawArrays(drawType, 0, points);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                /**
 | 
			
		||||
                 * Clear the chart.
 | 
			
		||||
                 */
 | 
			
		||||
                clear: function () {
 | 
			
		||||
                    // Set the viewport size; note that we use the width/height
 | 
			
		||||
                    // that our WebGL context reports, which may be lower
 | 
			
		||||
                    // resolution than the canvas we requested.
 | 
			
		||||
                    gl.viewport(
 | 
			
		||||
                        0,
 | 
			
		||||
                        0,
 | 
			
		||||
                        gl.drawingBufferWidth,
 | 
			
		||||
                        gl.drawingBufferHeight
 | 
			
		||||
                    );
 | 
			
		||||
                    gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT);
 | 
			
		||||
                },
 | 
			
		||||
                /**
 | 
			
		||||
                 * Set the logical boundaries of the chart.
 | 
			
		||||
                 * @param {number[]} dimensions the horizontal and
 | 
			
		||||
                 *        vertical dimensions of the chart
 | 
			
		||||
                 * @param {number[]} origin the horizontal/vertical
 | 
			
		||||
                 *        origin of the chart
 | 
			
		||||
                 */
 | 
			
		||||
                setDimensions: function (dimensions, origin) {
 | 
			
		||||
                    if (dimensions && dimensions.length > 0 &&
 | 
			
		||||
                            origin && origin.length > 0) {
 | 
			
		||||
                        gl.uniform2fv(uDimensions, dimensions);
 | 
			
		||||
                        gl.uniform2fv(uOrigin, origin);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                /**
 | 
			
		||||
                 * Draw the supplied buffer as a line strip (a sequence
 | 
			
		||||
                 * of line segments), in the chosen color.
 | 
			
		||||
                 * @param {Float32Array} buf the line strip to draw,
 | 
			
		||||
                 *        in alternating x/y positions
 | 
			
		||||
                 * @param {number[]} color the color to use when drawing
 | 
			
		||||
                 *        the line, as an RGBA color where each element
 | 
			
		||||
                 *        is in the range of 0.0-1.0
 | 
			
		||||
                 * @param {number} points the number of points to draw
 | 
			
		||||
                 */
 | 
			
		||||
                drawLine: function (buf, color, points) {
 | 
			
		||||
                    doDraw(gl.LINE_STRIP, buf, color, points);
 | 
			
		||||
                },
 | 
			
		||||
                /**
 | 
			
		||||
                 * Draw a rectangle extending from one corner to another,
 | 
			
		||||
                 * in the chosen color.
 | 
			
		||||
                 * @param {number[]} min the first corner of the rectangle
 | 
			
		||||
                 * @param {number[]} max the opposite corner
 | 
			
		||||
                 * @param {number[]} color the color to use when drawing
 | 
			
		||||
                 *        the rectangle, as an RGBA color where each element
 | 
			
		||||
                 *        is in the range of 0.0-1.0
 | 
			
		||||
                 */
 | 
			
		||||
                drawSquare: function (min, max, color) {
 | 
			
		||||
                    doDraw(gl.TRIANGLE_FAN, new Float32Array(
 | 
			
		||||
                        min.concat([min[0], max[1]]).concat(max).concat([max[0], min[1]])
 | 
			
		||||
                    ), color, 4);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        return DrawWebGL;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										75
									
								
								platform/features/plot-reborn/src/lib/utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								platform/features/plot-reborn/src/lib/utils.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define(function() {
 | 
			
		||||
    "use strict";
 | 
			
		||||
 | 
			
		||||
    var utils = {};
 | 
			
		||||
 | 
			
		||||
    utils.boxPointsFromOppositeCorners = function(start, end) {
 | 
			
		||||
        // Given two points defining opposite corners of a square,
 | 
			
		||||
        // return an array of points containing all of the boxes' rectangles.
 | 
			
		||||
        return [
 | 
			
		||||
            start,
 | 
			
		||||
            {domain: start.domain, range: end.range},
 | 
			
		||||
            end,
 | 
			
		||||
            {domain: end.domain, range: start.range}
 | 
			
		||||
        ];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    utils.oppositeCornersFromBoxPoints = function(boxPoints) {
 | 
			
		||||
        // Given an array of box points, return the topLeft and bottomRight points of the box.
 | 
			
		||||
        var topLeft = boxPoints.reduce(function(topLeft, currentPoint) {
 | 
			
		||||
            if (!topLeft) {
 | 
			
		||||
                return currentPoint;
 | 
			
		||||
            }
 | 
			
		||||
            if (currentPoint.domain <= topLeft.domain &&
 | 
			
		||||
                    currentPoint.range >= topLeft.range) {
 | 
			
		||||
                return currentPoint;
 | 
			
		||||
            }
 | 
			
		||||
            return topLeft;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        var bottomRight = boxPoints.reduce(function(bottomRight, currentPoint) {
 | 
			
		||||
            if (!bottomRight) {
 | 
			
		||||
                return currentPoint;
 | 
			
		||||
            }
 | 
			
		||||
            if (currentPoint.domain >= bottomRight.domain &&
 | 
			
		||||
                    currentPoint.range <= bottomRight.range) {
 | 
			
		||||
                return currentPoint;
 | 
			
		||||
            }
 | 
			
		||||
            return bottomRight;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            topLeft: topLeft,
 | 
			
		||||
            bottomRight: bottomRight
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    utils.elementPositionAsPlotPosition = function(elementPosition, elementBounds, viewport) {
 | 
			
		||||
        // Convert an (x, y) pair in element space to a
 | 
			
		||||
        // (domain, range) pair viewport.
 | 
			
		||||
 | 
			
		||||
        // Element space has (0,0) as the topLeft corner, With x
 | 
			
		||||
        // increasing to the right and y increasing to the bottom.
 | 
			
		||||
 | 
			
		||||
        var maxDomain = viewport.bottomRight.domain;
 | 
			
		||||
        var minDomain = viewport.topLeft.domain;
 | 
			
		||||
        var domainDenominator = maxDomain - minDomain;
 | 
			
		||||
 | 
			
		||||
        var maxRange = viewport.topLeft.range;
 | 
			
		||||
        var minRange = viewport.bottomRight.range;
 | 
			
		||||
        var rangeDenominator = maxRange - minRange;
 | 
			
		||||
 | 
			
		||||
        var xFraction = elementPosition.x / elementBounds.width;
 | 
			
		||||
        var yFraction = elementPosition.y / elementBounds.height;
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            domain: minDomain + domainDenominator * xFraction,
 | 
			
		||||
            range: maxRange - rangeDenominator * yFraction
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return utils;
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										154
									
								
								platform/features/plot-reborn/src/services/ColorService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								platform/features/plot-reborn/src/services/ColorService.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*global define*/
 | 
			
		||||
define(
 | 
			
		||||
    function () {
 | 
			
		||||
        'use strict';
 | 
			
		||||
 | 
			
		||||
        var COLOR_PALETTE = [
 | 
			
		||||
            [ 0x20, 0xB2, 0xAA ],
 | 
			
		||||
            [ 0x9A, 0xCD, 0x32 ],
 | 
			
		||||
            [ 0xFF, 0x8C, 0x00 ],
 | 
			
		||||
            [ 0xD2, 0xB4, 0x8C ],
 | 
			
		||||
            [ 0x40, 0xE0, 0xD0 ],
 | 
			
		||||
            [ 0x41, 0x69, 0xFF ],
 | 
			
		||||
            [ 0xFF, 0xD7, 0x00 ],
 | 
			
		||||
            [ 0x6A, 0x5A, 0xCD ],
 | 
			
		||||
            [ 0xEE, 0x82, 0xEE ],
 | 
			
		||||
            [ 0xCC, 0x99, 0x66 ],
 | 
			
		||||
            [ 0x99, 0xCC, 0xCC ],
 | 
			
		||||
            [ 0x66, 0xCC, 0x33 ],
 | 
			
		||||
            [ 0xFF, 0xCC, 0x00 ],
 | 
			
		||||
            [ 0xFF, 0x66, 0x33 ],
 | 
			
		||||
            [ 0xCC, 0x66, 0xFF ],
 | 
			
		||||
            [ 0xFF, 0x00, 0x66 ],
 | 
			
		||||
            [ 0xFF, 0xFF, 0x00 ],
 | 
			
		||||
            [ 0x80, 0x00, 0x80 ],
 | 
			
		||||
            [ 0x00, 0x86, 0x8B ],
 | 
			
		||||
            [ 0x00, 0x8A, 0x00 ],
 | 
			
		||||
            [ 0xFF, 0x00, 0x00 ],
 | 
			
		||||
            [ 0x00, 0x00, 0xFF ],
 | 
			
		||||
            [ 0xF5, 0xDE, 0xB3 ],
 | 
			
		||||
            [ 0xBC, 0x8F, 0x8F ],
 | 
			
		||||
            [ 0x46, 0x82, 0xB4 ],
 | 
			
		||||
            [ 0xFF, 0xAF, 0xAF ],
 | 
			
		||||
            [ 0x43, 0xCD, 0x80 ],
 | 
			
		||||
            [ 0xCD, 0xC1, 0xC5 ],
 | 
			
		||||
            [ 0xA0, 0x52, 0x2D ],
 | 
			
		||||
            [ 0x64, 0x95, 0xED ]
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A representation of a color that allows conversions between different
 | 
			
		||||
         * formats.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function Color(integerArray) {
 | 
			
		||||
            this.integerArray = integerArray;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Return color as a three element array of RGB values, where each value
 | 
			
		||||
         * is a integer in the range of 0-255.
 | 
			
		||||
         *
 | 
			
		||||
         * @return {number[]} the color, as integer RGB values
 | 
			
		||||
         */
 | 
			
		||||
        Color.prototype.asIntegerArray = function () {
 | 
			
		||||
            return this.integerArray.map(function (c) {
 | 
			
		||||
                return c;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
       /**
 | 
			
		||||
        * Return color as a string using #-prefixed six-digit RGB hex notation
 | 
			
		||||
        * (e.g. #FF0000).  See http://www.w3.org/TR/css3-color/#rgb-color.
 | 
			
		||||
        *
 | 
			
		||||
        * @return {string} the color, as a style-friendly string
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
        Color.prototype.asHexString = function () {
 | 
			
		||||
            return '#' + this.integerArray.map(function (c) {
 | 
			
		||||
                return (c < 16 ? '0' : '') + c.toString(16);
 | 
			
		||||
            }).join('');
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Return color as a RGBA float array.
 | 
			
		||||
         *
 | 
			
		||||
         * This format is present specifically to support use with
 | 
			
		||||
         * WebGL, which expects colors of that form.
 | 
			
		||||
         *
 | 
			
		||||
         * @return {number[]} the color, as floating-point RGBA values
 | 
			
		||||
         */
 | 
			
		||||
        Color.prototype.asRGBAArray = function () {
 | 
			
		||||
            return this.integerArray.map(function (c) {
 | 
			
		||||
                return c / 255.0;
 | 
			
		||||
            }).concat([1]);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A color palette stores a set of colors and allows for different
 | 
			
		||||
         * methods of color allocation.
 | 
			
		||||
         *
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function ColorPalette() {
 | 
			
		||||
            this.nextColor = 0;
 | 
			
		||||
            this.colors = COLOR_PALETTE.map(function (color) {
 | 
			
		||||
                return new Color(color);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * @returns {Color} the next unused color in the palette.  If all colors
 | 
			
		||||
         * have been allocated, it will wrap around.
 | 
			
		||||
         */
 | 
			
		||||
        ColorPalette.prototype.getNextColor = function () {
 | 
			
		||||
            var color = this.colors[this.nextColor % this.colors.length];
 | 
			
		||||
            this.nextColor++;
 | 
			
		||||
            return color;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * @param {number} index the index of the color to return.  An index
 | 
			
		||||
         * value larger than the size of the index will wrap around.
 | 
			
		||||
         * @returns {Color}
 | 
			
		||||
        */
 | 
			
		||||
        ColorPalette.prototype.getColor = function (index) {
 | 
			
		||||
            return this.colors[index % this.colors.length];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        function ColorService() {}
 | 
			
		||||
 | 
			
		||||
        ColorService.prototype.ColorPalette = ColorPalette;
 | 
			
		||||
        ColorService.prototype.Color = Color;
 | 
			
		||||
 | 
			
		||||
        function getColorService() {
 | 
			
		||||
            return new ColorService();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return getColorService;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -25,6 +25,7 @@
 | 
			
		||||
    <div class="gl-plot"
 | 
			
		||||
         ng-style="{ height: 100 / plot.getSubPlots().length + '%'}"
 | 
			
		||||
         ng-repeat="subplot in plot.getSubPlots()">
 | 
			
		||||
<!--         mct-pan="handlePan(position)">-->
 | 
			
		||||
        <div class="gl-plot-legend">
 | 
			
		||||
            <!-- ng-class is temporarily hard-coded in next element -->
 | 
			
		||||
            <span
 | 
			
		||||
@@ -42,7 +43,7 @@
 | 
			
		||||
        <div
 | 
			
		||||
            class="gl-plot-coords"
 | 
			
		||||
            ng-if="subplot.isHovering() && subplot.getHoverCoordinates()"
 | 
			
		||||
            >
 | 
			
		||||
             >
 | 
			
		||||
            {{subplot.getHoverCoordinates()}}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -177,7 +177,7 @@ define(
 | 
			
		||||
 | 
			
		||||
            // Unsubscribe when the plot is destroyed
 | 
			
		||||
            $scope.$on("$destroy", releaseSubscription);
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
            // Create a throttled update function
 | 
			
		||||
            scheduleUpdate = throttle(function () {
 | 
			
		||||
                modeOptions.getModeHandler().getSubPlots()
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "ELASTIC_ROOT",
 | 
			
		||||
                "value": "http://localhost:9200",
 | 
			
		||||
                "value": "/elastic",
 | 
			
		||||
                "priority": "fallback"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
            {
 | 
			
		||||
                "key": "menu",
 | 
			
		||||
                "implementation": "gestures/ContextMenuGesture.js",
 | 
			
		||||
                "depends": []
 | 
			
		||||
                "depends": ["$timeout", "agentService"]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "components": [
 | 
			
		||||
@@ -54,7 +54,7 @@
 | 
			
		||||
            {
 | 
			
		||||
                "key": "menu",
 | 
			
		||||
                "implementation": "actions/ContextMenuAction.js",
 | 
			
		||||
                "depends": [ "$compile", "$document", "$window", "$rootScope" ]
 | 
			
		||||
                "depends": [ "$compile", "$document", "$window", "$rootScope", "agentService" ]
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ define(
 | 
			
		||||
         * @param actionContexr the context in which the action
 | 
			
		||||
         *                      should be performed
 | 
			
		||||
         */
 | 
			
		||||
        function ContextMenuAction($compile, $document, $window, $rootScope, actionContext) {
 | 
			
		||||
        function ContextMenuAction($compile, $document, $window, $rootScope, agentService, actionContext) {
 | 
			
		||||
            
 | 
			
		||||
            function perform() {
 | 
			
		||||
                var winDim = [$window.innerWidth, $window.innerHeight],
 | 
			
		||||
@@ -94,13 +94,26 @@ define(
 | 
			
		||||
                body.append(menu);
 | 
			
		||||
                
 | 
			
		||||
                // Stop propagation so that clicks on the menu do not close the menu
 | 
			
		||||
                menu.on('mousedown', function (event) {
 | 
			
		||||
                    event.stopPropagation();
 | 
			
		||||
                });
 | 
			
		||||
                // Stop propagation so that touches on the menu do not close the menu
 | 
			
		||||
                if (!agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                    menu.on('mousedown', function (event) {
 | 
			
		||||
                        event.stopPropagation();
 | 
			
		||||
                    });
 | 
			
		||||
                } else if (agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                    menu.on('touchstart', function (event) {
 | 
			
		||||
                        event.stopPropagation();
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Dismiss the menu when body is clicked elsewhere
 | 
			
		||||
                // Dismiss the menu when body is clicked/touched elsewhere
 | 
			
		||||
                // ('mousedown' because 'click' breaks left-click context menus)
 | 
			
		||||
                body.on('mousedown', dismiss);
 | 
			
		||||
                // ('touchstart' because 'touch' breaks context menus up)
 | 
			
		||||
                if (!agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                    body.on('mousedown', dismiss);
 | 
			
		||||
                } else if (agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                    body.on('touchstart', dismiss);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // Don't launch browser's context menu
 | 
			
		||||
                actionContext.event.preventDefault();
 | 
			
		||||
 
 | 
			
		||||
@@ -39,16 +39,40 @@ define(
 | 
			
		||||
         * @param {DomainObject} domainObject the object on which actions
 | 
			
		||||
         *                       in the context menu will be performed
 | 
			
		||||
         */
 | 
			
		||||
        function ContextMenuGesture(element, domainObject) {
 | 
			
		||||
        function ContextMenuGesture($timeout, agentService, element, domainObject) {
 | 
			
		||||
            var actionContext,
 | 
			
		||||
                stop;
 | 
			
		||||
                stop,
 | 
			
		||||
                isPressing,
 | 
			
		||||
                longTouchTime = 500;
 | 
			
		||||
            
 | 
			
		||||
            // When context menu event occurs, show object actions instead
 | 
			
		||||
            element.on('contextmenu', function (event) {
 | 
			
		||||
                actionContext = {key: 'menu', domainObject: domainObject, event: event};
 | 
			
		||||
                stop = domainObject.getCapability('action').perform(actionContext);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            if (!agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                element.on('contextmenu', function (event) {
 | 
			
		||||
                    actionContext = {key: 'menu', domainObject: domainObject, event: event};
 | 
			
		||||
                    stop = domainObject.getCapability('action').perform(actionContext);
 | 
			
		||||
                });
 | 
			
		||||
            } else if (agentService.isMobile(navigator.userAgent)) {
 | 
			
		||||
                // If on mobile device, then start timeout for the single touch event
 | 
			
		||||
                // during the timeout 'isPressing' is true.
 | 
			
		||||
                element.on('touchstart', function (event) {
 | 
			
		||||
                    if (event.touches.length < 2) {
 | 
			
		||||
                        isPressing = true;
 | 
			
		||||
                        // After the timeout, if 'isPressing' is
 | 
			
		||||
                        // true, display context menu for object
 | 
			
		||||
                        $timeout(function () {
 | 
			
		||||
                            if (isPressing) {
 | 
			
		||||
                                actionContext = {key: 'menu', domainObject: domainObject, event: event};
 | 
			
		||||
                                stop = domainObject.getCapability('action').perform(actionContext);
 | 
			
		||||
                            }
 | 
			
		||||
                        }, longTouchTime);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                // Whenever the touch event ends, 'isPressing' is false.
 | 
			
		||||
                element.on('touchend', function (event) {
 | 
			
		||||
                    isPressing = false;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                /**
 | 
			
		||||
                 * Detach any event handlers associated with this gesture.
 | 
			
		||||
 
 | 
			
		||||
@@ -43,13 +43,24 @@ define(
 | 
			
		||||
                mockBody,
 | 
			
		||||
                mockWindow,
 | 
			
		||||
                mockRootScope,
 | 
			
		||||
                mockAgentService,
 | 
			
		||||
                mockScope,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockEvent,
 | 
			
		||||
                mockActionContext,
 | 
			
		||||
                mockNavigator,
 | 
			
		||||
                mockStopPropagation,
 | 
			
		||||
                action;
 | 
			
		||||
 | 
			
		||||
            function fireEvent(evt, value) {
 | 
			
		||||
                mockElement.on.calls.forEach(function (call) {
 | 
			
		||||
                    if (call.args[0] === evt) {
 | 
			
		||||
                        call.args[1](value);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockCompile = jasmine.createSpy("$compile");
 | 
			
		||||
                mockCompiledTemplate = jasmine.createSpy("template");
 | 
			
		||||
@@ -58,10 +69,11 @@ define(
 | 
			
		||||
                mockBody = jasmine.createSpyObj("body", JQLITE_FUNCTIONS);
 | 
			
		||||
                mockWindow = { innerWidth: MENU_DIMENSIONS[0] * 4, innerHeight: MENU_DIMENSIONS[1] * 4 };
 | 
			
		||||
                mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
 | 
			
		||||
                mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
 | 
			
		||||
                mockScope = {};
 | 
			
		||||
                mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
 | 
			
		||||
                mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
 | 
			
		||||
                mockEvent = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
 | 
			
		||||
                mockEvent.pageX = 0;
 | 
			
		||||
                mockEvent.pageY = 0;
 | 
			
		||||
 | 
			
		||||
@@ -71,12 +83,13 @@ define(
 | 
			
		||||
                mockRootScope.$new.andReturn(mockScope);
 | 
			
		||||
                
 | 
			
		||||
                mockActionContext = {key: 'menu', domainObject: mockDomainObject, event: mockEvent};
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
                action = new ContextMenuAction(
 | 
			
		||||
                    mockCompile,
 | 
			
		||||
                    mockDocument,
 | 
			
		||||
                    mockWindow,
 | 
			
		||||
                    mockRootScope,
 | 
			
		||||
                    mockAgentService,
 | 
			
		||||
                    mockActionContext
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
@@ -135,6 +148,42 @@ define(
 | 
			
		||||
                // Listener should have been detached from body
 | 
			
		||||
                expect(mockBody.off).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("keeps a menu when menu is clicked", function () {
 | 
			
		||||
                // Show the menu
 | 
			
		||||
                action.perform();
 | 
			
		||||
                // Find and fire body's mousedown listener
 | 
			
		||||
                mockMenu.on.calls.forEach(function (call) {
 | 
			
		||||
                    if (call.args[0] === 'mousedown') {
 | 
			
		||||
                        call.args[1](mockEvent);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Menu should have been removed
 | 
			
		||||
                expect(mockMenu.remove).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                // Listener should have been detached from body
 | 
			
		||||
                expect(mockBody.off).not.toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("keeps a menu when menu is clicked on mobile", function () {
 | 
			
		||||
                mockAgentService.isMobile.andReturn(true);
 | 
			
		||||
                action = new ContextMenuAction(
 | 
			
		||||
                    mockCompile,
 | 
			
		||||
                    mockDocument,
 | 
			
		||||
                    mockWindow,
 | 
			
		||||
                    mockRootScope,
 | 
			
		||||
                    mockAgentService,
 | 
			
		||||
                    mockActionContext
 | 
			
		||||
                );
 | 
			
		||||
                action.perform();
 | 
			
		||||
                
 | 
			
		||||
                mockMenu.on.calls.forEach(function (call) {
 | 
			
		||||
                    if (call.args[0] === 'touchstart') {
 | 
			
		||||
                        call.args[1](mockEvent);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -31,28 +31,54 @@ define(
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        var JQLITE_FUNCTIONS = [ "on", "off", "find", "append", "remove" ],
 | 
			
		||||
            DOMAIN_OBJECT_METHODS = [ "getId", "getModel", "getCapability", "hasCapability", "useCapability" ];
 | 
			
		||||
            DOMAIN_OBJECT_METHODS = [ "getId", "getModel", "getCapability", "hasCapability", "useCapability"];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        describe("The 'context menu' gesture", function () {
 | 
			
		||||
            var mockElement,
 | 
			
		||||
            var mockTimeout,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                mockAgentService,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockEvent,
 | 
			
		||||
                mockTouchEvent,
 | 
			
		||||
                mockContextMenuAction,
 | 
			
		||||
                mockActionContext,
 | 
			
		||||
                mockTouch,
 | 
			
		||||
                gesture,
 | 
			
		||||
                fireGesture;
 | 
			
		||||
                fireGesture,
 | 
			
		||||
                fireTouchStartGesture,
 | 
			
		||||
                fireTouchEndGesture;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockTimeout = jasmine.createSpy("$timeout");
 | 
			
		||||
                mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
 | 
			
		||||
                mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
 | 
			
		||||
                mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
 | 
			
		||||
 | 
			
		||||
                gesture = new ContextMenuGesture(mockElement, mockDomainObject);
 | 
			
		||||
                mockContextMenuAction = jasmine.createSpyObj(
 | 
			
		||||
                    "action",
 | 
			
		||||
                    [ "perform", "getActions" ]
 | 
			
		||||
                );
 | 
			
		||||
                mockActionContext = jasmine.createSpyObj(
 | 
			
		||||
                    "actionContext",
 | 
			
		||||
                    [ "" ]
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                mockActionContext = {domainObject: mockDomainObject, event: mockEvent};
 | 
			
		||||
                mockDomainObject.getCapability.andReturn(mockContextMenuAction);
 | 
			
		||||
                mockContextMenuAction.perform.andReturn(jasmine.any(Function));
 | 
			
		||||
                mockAgentService.isMobile.andReturn(false);
 | 
			
		||||
                
 | 
			
		||||
                
 | 
			
		||||
                gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
 | 
			
		||||
 | 
			
		||||
                // Capture the contextmenu callback
 | 
			
		||||
                fireGesture =  mockElement.on.mostRecentCall.args[1];
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("attaches a callback for context menu events", function () {
 | 
			
		||||
                // Fire a click and expect it to happen
 | 
			
		||||
                fireGesture();
 | 
			
		||||
                expect(mockElement.on).toHaveBeenCalledWith(
 | 
			
		||||
                    "contextmenu",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
@@ -70,6 +96,34 @@ define(
 | 
			
		||||
                    mockDomainObject.calls
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            it("attaches a callback for context menu events on mobile", function () {
 | 
			
		||||
                // Mock touch event and set to mobile device
 | 
			
		||||
                mockTouchEvent = jasmine.createSpyObj("event", ["preventDefault", "touches"]);
 | 
			
		||||
                mockTouch = jasmine.createSpyObj("touch", ["length"]);
 | 
			
		||||
                mockTouch.length = 1;
 | 
			
		||||
                mockTouchEvent.touches.andReturn(mockTouch);
 | 
			
		||||
                mockAgentService.isMobile.andReturn(true);
 | 
			
		||||
                
 | 
			
		||||
                // Then create new (mobile) gesture
 | 
			
		||||
                gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
 | 
			
		||||
                
 | 
			
		||||
                // Set calls for the touchstart and touchend gestures
 | 
			
		||||
                fireTouchStartGesture = mockElement.on.calls[1].args[1];
 | 
			
		||||
                fireTouchEndGesture =  mockElement.on.mostRecentCall.args[1];
 | 
			
		||||
                
 | 
			
		||||
                // Fire touchstart and expect touch start to begin
 | 
			
		||||
                fireTouchStartGesture(mockTouchEvent);
 | 
			
		||||
                expect(mockElement.on).toHaveBeenCalledWith(
 | 
			
		||||
                    "touchstart",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
                
 | 
			
		||||
                // Expect timeout to begin and then fireTouchEnd
 | 
			
		||||
                expect(mockTimeout).toHaveBeenCalled();
 | 
			
		||||
                mockTimeout.mostRecentCall.args[0]();
 | 
			
		||||
                fireTouchEndGesture(mockTouchEvent);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
		Reference in New Issue
	
	Block a user