Merge remote-tracking branch 'origin/mobile_3' into mobile

This commit is contained in:
Shivam Dave 2015-08-05 12:17:49 -07:00
commit a146185bd2
32 changed files with 577 additions and 143 deletions

View File

@ -24,5 +24,5 @@
<span ng-controller="BrowseController"
ng-click='backArrow()'
ng-class="checkRoot(); atRoot ? 'mobile-back-hide' : 'mobile-back-unhide'">
<a class='type-icon icon ui-symbol'>&lt;</a>
<a class='type-icon icon ui-symbol'>{</a>
</span>

View File

@ -20,8 +20,8 @@
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>
@ -44,4 +44,7 @@
</div>
</div>
</div>
</div>
<div class="contents abs mobile-info">
<mct-representation class="contents abs btn s-very-subtle desktop-hide" key="'info-button'" mct-object="domainObject"></mct-representation>
</div>
</div>

View File

@ -10,8 +10,8 @@
"depends": [ "$location" ]
},
{
"key": "queryService",
"implementation": "/services/QueryService.js",
"key": "agentService",
"implementation": "/services/AgentService.js",
"depends": [ "$window" ]
}
],
@ -65,7 +65,7 @@
{
"key": "TreeNodeController",
"implementation": "controllers/TreeNodeController.js",
"depends": [ "$scope", "$timeout", "queryService" ]
"depends": [ "$scope", "$timeout", "agentService" ]
},
{
"key": "ActionGroupController",

View File

@ -367,21 +367,33 @@
* 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 35, ../sass/mobile/_item.scss */
/* 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 41, ../sass/mobile/_item.scss */
/* 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 48, ../sass/mobile/_item.scss */
/* line 61, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .item-main .item-open {
display: none; }
/* line 52, ../sass/mobile/_item.scss */
/* 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) {
@ -389,14 +401,17 @@
.items-holder .item.grid-item {
width: 100%;
height: 50px; }
/* line 62, ../sass/mobile/_item.scss */
/* line 74, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .mobile-info {
line-height: 25px; }
/* line 78, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .item-main .item-type {
line-height: 40px; }
/* line 66, ../sass/mobile/_item.scss */
/* line 82, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .title {
margin-right: 10px;
line-height: 25px; }
/* line 70, ../sass/mobile/_item.scss */
/* line 86, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .details {
margin-right: 10px;
line-height: 0px; } }
@ -405,15 +420,18 @@
.items-holder .item.grid-item {
width: 100%;
height: 66.66667px; }
/* line 81, ../sass/mobile/_item.scss */
/* line 96, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .mobile-info {
line-height: 38px; }
/* line 100, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .item-main .item-type {
font-size: 30px;
line-height: 50px; }
/* line 86, ../sass/mobile/_item.scss */
/* line 105, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .title {
margin-right: 10px;
line-height: 38px; }
/* line 90, ../sass/mobile/_item.scss */
/* line 109, ../sass/mobile/_item.scss */
.items-holder .item.grid-item .details {
margin-right: 10px;
line-height: 0px; } }

View File

@ -4432,6 +4432,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
@ -4757,33 +4768,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%;
@ -4791,21 +4809,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;
@ -4813,7 +4831,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;
@ -4824,22 +4842,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; }

View File

@ -344,14 +344,16 @@ ul.tree {
right: 13px;
font-size: 1.8em;
right: 0px;
width: auto; }
/* line 44, ../sass/mobile/_tree.scss */
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 51, ../sass/mobile/_tree.scss */
/* line 54, ../sass/mobile/_tree.scss */
ul.tree li span.tree-item .label .title-label {
right: 16.9px; }
/* line 60, ../sass/mobile/_tree.scss */
/* line 63, ../sass/mobile/_tree.scss */
ul.tree ul.tree {
margin-left: 7px; } }

View File

@ -64,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";

View File

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

View File

@ -31,11 +31,24 @@
$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 {
@ -51,13 +64,16 @@
}
.title, .details {
margin-left: $mobile-listIcon;
}
}
}
@include phone {
$dHei: $phone-itemHeight;
width: $dWid;
height: $dHei;
.mobile-info {
line-height: $phone-itemHeight * .5;
}
.item-main {
.item-type {
line-height: $phone-itemHeight * .8;
@ -77,6 +93,9 @@
$dHei: $tablet-itemHeight;
width: $dWid;
height: $dHei;
.mobile-info {
line-height: $tablet-itemHeight * .57;
}
.item-main {
.item-type {
font-size: $mobile-listIcon;

View File

@ -75,7 +75,18 @@
#{$phoneLandscapeEmu},
#{$tabletPortrait},
#{$tabletLandscape},
#{$tabletLandscapeEmu}{
#{$tabletLandscapeEmu} {
@content
}
}
// Desktop monitors in any orientation
@mixin desktopandtablet {
@media #{$tabletPortrait},
#{$tabletLandscape},
#{$tabletLandscapeEmu},
#{$desktopPortrait},
#{$desktopLandscape} {
@content
}
}

View File

@ -38,19 +38,22 @@ ul.tree {
right: $mobile-treeRight;
font-size: 1.8em;
right: 0px;
width: auto;
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;
}
}
}
}
}

View File

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

View File

@ -41,7 +41,7 @@
toggle.toggle(); treeNode.trackExpansion()"
ng-if="model.composition !== undefined || treeNode.checkMobile()"
>
{{treeNode.checkMobile() ? ">" : toggle.isActive() ? "v" : ">"}}
{{treeNode.checkMobile() ? "}" : toggle.isActive() ? "v" : ">"}}
</span>
</span>
<span

View File

@ -50,7 +50,7 @@ define(
* expand-to-show-navigated-object behavior.)
* @constructor
*/
function TreeNodeController($scope, $timeout, queryService) {
function TreeNodeController($scope, $timeout, agentService) {
var selectedObject = ($scope.ngModel || {}).selectedObject,
isSelected = false,
hasBeenExpanded = false;
@ -88,7 +88,7 @@ define(
}
function checkMobile() {
return queryService.isMobile(navigator.userAgent);
return agentService.isMobile(navigator.userAgent);
}
// Consider the currently-navigated object and update

View File

@ -22,7 +22,7 @@
/*global define,Promise*/
/**
* Module defining QueryService.
* Module defining AgentService.
*/
define(
@ -35,7 +35,7 @@ define(
* info using a comparison between the userAgent and key
* device names
*/
function QueryService($window) {
function AgentService($window) {
// Gets the UA name if it is one of the following.
// If it is not (a desktop for example) nothing is
@ -54,6 +54,17 @@ define(
return false;
}
}
// Checks if device is phone,
// phone is designated as only an
// iPhone device
function isPhone(ua) {
if (getDeviceUA(ua) == "iPhone") {
return true;
} else {
return false;
}
}
// Returns the orientation of the device based on the
// device's window dimensions
@ -76,10 +87,16 @@ define(
* on a mobile or non-mobile device. (mobile: true,
* non-mobile: false)
*/
isMobile: isMobile
isMobile: isMobile,
/**
* Returns the a boolean checking if the user is on
* a phone device. (phone: true, non-phone: false)
*/
isPhone: isPhone
};
}
return QueryService;
return AgentService;
}
);

View File

@ -29,7 +29,7 @@ define(
describe("The tree node controller", function () {
var mockScope,
mockTimeout,
mockQueryService,
mockAgentService,
controller;
function TestObject(id, context) {
@ -44,8 +44,8 @@ define(
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", ["$watch", "$on"]);
mockTimeout = jasmine.createSpy("$timeout");
mockQueryService = jasmine.createSpyObj("queryService", ["isMobile"]);
controller = new TreeNodeController(mockScope, mockTimeout, mockQueryService);
mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
controller = new TreeNodeController(mockScope, mockTimeout, mockAgentService);
});
it("allows tracking of expansion state", function () {

View File

@ -25,12 +25,12 @@
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/services/QueryService"],
function (QueryService) {
["../../src/services/AgentService"],
function (AgentService) {
"use strict";
describe("The url service", function () {
var queryService,
var agentService,
mockWindow,
mockNavigator;
@ -47,24 +47,27 @@ define(
[ "userAgent" ]
);
queryService = new QueryService(mockWindow);
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";
queryService.isMobile(mockNavigator.userAgent);
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";
queryService.isMobile(mockNavigator.userAgent);
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;
queryService.getOrientation();
agentService.getOrientation();
mockWindow.outerWidth = 1024;
mockWindow.outerHeight = 768;
queryService.getOrientation();
agentService.getOrientation();
});
});
}

View File

@ -13,7 +13,7 @@
"directives/MCTDrag",
"directives/MCTResize",
"directives/MCTScroll",
"services/QueryService",
"services/AgentService",
"services/UrlService",
"StyleSheetLoader"
]

View File

@ -24,10 +24,19 @@
"implementation": "gestures/InfoGesture.js",
"depends": [
"$timeout",
"queryService",
"agentService",
"infoService",
"INFO_HOVER_DELAY"
]
},
{
"key": "infobutton",
"implementation": "gestures/InfoButtonGesture.js",
"depends": [
"$document",
"agentService",
"infoService"
]
}
],
"services": [
@ -38,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" ]
}
]
}
}

View 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>

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

View File

@ -38,7 +38,7 @@ define(
* @param {DomainObject} domainObject the domain object for which to
* show information
*/
function InfoGesture($timeout, queryService, infoService, DELAY, element, domainObject) {
function InfoGesture($timeout, agentService, infoService, DELAY, element, domainObject) {
var dismissBubble,
pendingBubble,
mousePosition,
@ -93,9 +93,9 @@ define(
}
// Checks if you are on a mobile device, if the device is
// not mobile (queryService.isMobile() = false), then
// not mobile (agentService.isMobile() = false), then
// the pendingBubble and therefore hovering is allowed
if (!queryService.isMobile(navigator.userAgent)) {
if (!agentService.isMobile(navigator.userAgent)) {
// Show bubble (on a timeout) on mouse over
element.on('mouseenter', showBubble);
}

View File

@ -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', 0 + 'px');
bubble.css('left', 0 + 'px');
bubble.css('top', 'auto');
bubble.css('bottom', 25 + 'px');
} 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(); };
}

View File

@ -0,0 +1,116 @@
/*****************************************************************************
* 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,
mockAgentService,
mockInfoService,
testDelay = 12321,
mockElement,
mockDomainObject,
mockEvent,
mockScope,
mockOff,
testMetadata,
mockPromise,
mockHide,
gesture;
function fireEvent(evt, value) {
mockElement.on.calls.forEach(function (call) {
if (call.args[0] === evt) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockTimeout = jasmine.createSpy('$timeout');
mockDocument = jasmine.createSpyObj('$document', ['find']);
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' ]
);
mockDocument = jasmine.createSpyObj('$document', ['find']);
mockAgentService = jasmine.createSpyObj('agentService', ['isMobile']);
mockInfoService = jasmine.createSpyObj(
'infoService',
[ 'display' ]
);
mockElement = jasmine.createSpyObj(
'element',
[ 'on', 'off', 'scope', 'css', 'click' ]
);
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
);
});
it("expect click on the representation", function () {
expect(mockElement.on)
.toHaveBeenCalledWith('click', jasmine.any(Function));
});
});
}
);

View File

@ -28,7 +28,7 @@ define(
describe("The info gesture", function () {
var mockTimeout,
mockQueryService,
mockAgentService,
mockInfoService,
testDelay = 12321,
mockElement,
@ -51,7 +51,7 @@ define(
beforeEach(function () {
mockTimeout = jasmine.createSpy('$timeout');
mockTimeout.cancel = jasmine.createSpy('cancel');
mockQueryService = jasmine.createSpyObj('queryService', ['isMobile']);
mockAgentService = jasmine.createSpyObj('agentService', ['isMobile']);
mockInfoService = jasmine.createSpyObj(
'infoService',
[ 'display' ]
@ -81,7 +81,7 @@ define(
gesture = new InfoGesture(
mockTimeout,
mockQueryService,
mockAgentService,
mockInfoService,
testDelay,
mockElement,

View File

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

View File

@ -1,4 +1,5 @@
[
"gestures/InfoGesture",
"gestures/InfoButtonGesture",
"services/InfoService"
]

View File

@ -26,7 +26,7 @@
{
"key": "menu",
"implementation": "gestures/ContextMenuGesture.js",
"depends": ["$timeout", "queryService"]
"depends": ["$timeout", "agentService"]
}
],
"components": [
@ -54,7 +54,7 @@
{
"key": "menu",
"implementation": "actions/ContextMenuAction.js",
"depends": [ "$compile", "$document", "$window", "$rootScope", "queryService" ]
"depends": [ "$compile", "$document", "$window", "$rootScope", "agentService" ]
}
]
}

View File

@ -47,7 +47,7 @@ define(
* @param actionContexr the context in which the action
* should be performed
*/
function ContextMenuAction($compile, $document, $window, $rootScope, queryService, actionContext) {
function ContextMenuAction($compile, $document, $window, $rootScope, agentService, actionContext) {
function perform() {
var winDim = [$window.innerWidth, $window.innerHeight],
@ -95,11 +95,11 @@ define(
// Stop propagation so that clicks on the menu do not close the menu
// Stop propagation so that touches on the menu do not close the menu
if (!queryService.isMobile(navigator.userAgent)) {
if (!agentService.isMobile(navigator.userAgent)) {
menu.on('mousedown', function (event) {
event.stopPropagation();
});
} else if (queryService.isMobile(navigator.userAgent)) {
} else if (agentService.isMobile(navigator.userAgent)) {
menu.on('touchstart', function (event) {
event.stopPropagation();
});
@ -108,9 +108,9 @@ define(
// Dismiss the menu when body is clicked/touched elsewhere
// ('mousedown' because 'click' breaks left-click context menus)
// ('touchstart' because 'touch' breaks context menus up)
if (!queryService.isMobile(navigator.userAgent)) {
if (!agentService.isMobile(navigator.userAgent)) {
body.on('mousedown', dismiss);
} else if (queryService.isMobile(navigator.userAgent)) {
} else if (agentService.isMobile(navigator.userAgent)) {
body.on('touchstart', dismiss);
}

View File

@ -39,19 +39,19 @@ define(
* @param {DomainObject} domainObject the object on which actions
* in the context menu will be performed
*/
function ContextMenuGesture($timeout, queryService, element, domainObject) {
function ContextMenuGesture($timeout, agentService, element, domainObject) {
var actionContext,
stop,
isPressing,
longTouchTime = 500;
// When context menu event occurs, show object actions instead
if (!queryService.isMobile(navigator.userAgent)) {
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 (queryService.isMobile(navigator.userAgent)) {
} 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) {

View File

@ -43,7 +43,7 @@ define(
mockBody,
mockWindow,
mockRootScope,
mockQueryService,
mockAgentService,
mockScope,
mockElement,
mockDomainObject,
@ -53,6 +53,14 @@ define(
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");
@ -61,7 +69,7 @@ define(
mockBody = jasmine.createSpyObj("body", JQLITE_FUNCTIONS);
mockWindow = { innerWidth: MENU_DIMENSIONS[0] * 4, innerHeight: MENU_DIMENSIONS[1] * 4 };
mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
mockQueryService = jasmine.createSpyObj("queryService", ["isMobile"]);
mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
mockScope = {};
mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
@ -81,7 +89,7 @@ define(
mockDocument,
mockWindow,
mockRootScope,
mockQueryService,
mockAgentService,
mockActionContext
);
});
@ -144,13 +152,12 @@ define(
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]();
// }
// });
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();
@ -159,23 +166,23 @@ define(
expect(mockBody.off).not.toHaveBeenCalled();
});
it("mobile", function () {
mockQueryService.isMobile.andReturn(true);
it("keeps a menu when menu is clicked on mobile", function () {
mockAgentService.isMobile.andReturn(true);
action = new ContextMenuAction(
mockCompile,
mockDocument,
mockWindow,
mockRootScope,
mockQueryService,
mockAgentService,
mockActionContext
);
action.perform();
// mockMenu.on.calls.forEach(function (call) {
// if (call.args[0] === 'touchstart') {
// call.args[1]();
// }
// });
mockMenu.on.calls.forEach(function (call) {
if (call.args[0] === 'touchstart') {
call.args[1](mockEvent);
}
});
});
});
}

View File

@ -37,7 +37,7 @@ define(
describe("The 'context menu' gesture", function () {
var mockTimeout,
mockElement,
mockQueryService,
mockAgentService,
mockDomainObject,
mockEvent,
gesture,
@ -46,11 +46,11 @@ define(
beforeEach(function () {
mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
mockTimeout = jasmine.createSpy("$timeout");
mockQueryService = jasmine.createSpyObj("queryService", ["isMobile"]);
mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
gesture = new ContextMenuGesture(mockTimeout, mockQueryService, mockElement, mockDomainObject);
gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
// Capture the contextmenu callback
fireGesture = mockElement.on.mostRecentCall.args[1];
@ -76,16 +76,11 @@ define(
});
it("mobile", function () {
mockQueryService.isMobile.andReturn(true);
gesture = new ContextMenuGesture(mockTimeout, mockQueryService, mockElement, mockDomainObject);
mockAgentService.isMobile.andReturn(true);
gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
// Capture the contextmenu callback
fireGesture = mockElement.on.mostRecentCall.args[1];
expect(mockElement.on).toHaveBeenCalledWith(
"touchstart",
jasmine.any(Function)
);
});
});
}