From 8dad6a3fd5b2b1e9fcd867cb17c8218f6f6b2b7f Mon Sep 17 00:00:00 2001 From: slhale Date: Wed, 19 Aug 2015 13:04:11 -0700 Subject: [PATCH] Merge browse files from branch 'mobile' into open72 --- .../commonUI/browse/res/templates/browse.html | 31 +-- .../commonUI/browse/src/BrowseController.js | 43 +++- .../browse/test/BrowseControllerSpec.js | 122 +++++++++- .../general/res/sass/mobile/_layout.scss | 222 ++++++++++++++++++ 4 files changed, 400 insertions(+), 18 deletions(-) create mode 100644 platform/commonUI/general/res/sass/mobile/_layout.scss diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index 3ac082fc59..2aadc0234e 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -19,30 +19,33 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> -
+ +
-
+
-
- - -
+
+
-
- -
-
- + -
+ + +
+
+ + +
+
m
+
+ diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js index 3ec38057fc..c61260a400 100644 --- a/platform/commonUI/browse/src/BrowseController.js +++ b/platform/commonUI/browse/src/BrowseController.js @@ -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; } diff --git a/platform/commonUI/browse/test/BrowseControllerSpec.js b/platform/commonUI/browse/test/BrowseControllerSpec.js index ce9296c239..722b7b4132 100644 --- a/platform/commonUI/browse/test/BrowseControllerSpec.js +++ b/platform/commonUI/browse/test/BrowseControllerSpec.js @@ -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(); + }); }); } ); diff --git a/platform/commonUI/general/res/sass/mobile/_layout.scss b/platform/commonUI/general/res/sass/mobile/_layout.scss new file mode 100644 index 0000000000..3f4fc062d3 --- /dev/null +++ b/platform/commonUI/general/res/sass/mobile/_layout.scss @@ -0,0 +1,222 @@ +/***************************************************************************** + * 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 { + @include phoneandtablet { + pointer-events: none; + @include trans-prop-nice(opacity, .4s); + opacity: 0; + } +} + +// Hides objects on phone and tablet +.mobile-back-unhide { + @include phoneandtablet { + 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); + } +}