Compare commits
	
		
			215 Commits
		
	
	
		
			fix-fileSa
			...
			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