Merge browse files from branch 'mobile' into open72

This commit is contained in:
slhale 2015-08-19 13:04:11 -07:00
parent f4b87cf70d
commit 8dad6a3fd5
4 changed files with 400 additions and 18 deletions

View File

@ -19,30 +19,33 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. 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> <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'> <mct-split-pane class='contents abs' anchor='left'>
<div <div class='split-pane-component treeview pane mobile-pane left-menu desktop-browse'>
class='split-pane-component treeview pane left' <div class='holder tree-holder abs mobile-tree-holder'>
>
<mct-representation key="'create-button'" mct-object="navigatedObject">
</mct-representation>
<div class='holder tree-holder abs'>
<mct-representation key="'tree'" <mct-representation key="'tree'"
mct-object="domainObject" mct-object="domainObject"
ng-model="treeModel"> ng-model="treeModel">
</mct-representation> </mct-representation>
</div> </div>
</div> <mct-representation key="'create-button'" mct-object="navigatedObject">
<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> </mct-representation>
</div>
</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> </mct-split-pane>
</div> </div>
<mct-include key="'bottombar'"></mct-include> <mct-include key="'bottombar'"></mct-include>
</div> </div>

View File

@ -63,7 +63,6 @@ define(
// path to new, addressed, path based on // path to new, addressed, path based on
// domainObject // domainObject
$location.path(urlService.urlForLocation("browse", domainObject)); $location.path(urlService.urlForLocation("browse", domainObject));
} }
// Callback for updating the in-scope reference to the object // Callback for updating the in-scope reference to the object
@ -126,6 +125,36 @@ define(
navigateTo(domainObject); 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. // Load the root object, put it in the scope.
// Also, load its immediate children, and (possibly) // Also, load its immediate children, and (possibly)
@ -140,7 +169,13 @@ define(
$scope.treeModel = { $scope.treeModel = {
selectedObject: navigationService.getNavigation() 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. // Listen for changes in navigation state.
navigationService.addListener(setNavigation); navigationService.addListener(setNavigation);
@ -151,6 +186,10 @@ define(
$scope.$on("$destroy", function () { $scope.$on("$destroy", function () {
navigationService.removeListener(setNavigation); navigationService.removeListener(setNavigation);
}); });
$scope.backArrow = navigateToParent;
$scope.checkRoot = checkRoot;
} }

View File

@ -39,6 +39,9 @@ define(
mockUrlService, mockUrlService,
mockDomainObject, mockDomainObject,
mockNextObject, mockNextObject,
mockParentContext,
mockParent,
mockGrandparent,
controller; controller;
function mockPromise(value) { function mockPromise(value) {
@ -52,7 +55,7 @@ define(
beforeEach(function () { beforeEach(function () {
mockScope = jasmine.createSpyObj( mockScope = jasmine.createSpyObj(
"$scope", "$scope",
[ "$on", "$watch" ] [ "$on", "$watch", "treeSlide", "backArrow" ]
); );
mockRoute = { current: { params: {} } }; mockRoute = { current: { params: {} } };
mockLocation = jasmine.createSpyObj( mockLocation = jasmine.createSpyObj(
@ -88,6 +91,17 @@ define(
"nextObject", "nextObject",
[ "getId", "getCapability", "getModel", "useCapability" ] [ "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({ mockObjectService.getObjects.andReturn(mockPromise({
ROOT: mockRootObject ROOT: mockRootObject
@ -145,6 +159,13 @@ define(
); );
expect(mockScope.navigatedObject).toEqual(mockDomainObject); 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 () { it("releases its navigation listener when its scope is destroyed", function () {
expect(mockScope.$on).toHaveBeenCalledWith( expect(mockScope.$on).toHaveBeenCalledWith(
@ -237,7 +258,104 @@ define(
mockUrlService.urlForLocation(mockMode, mockNextObject) 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();
});
}); });
} }
); );

View File

@ -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);
}
}