mirror of
https://github.com/nasa/openmct.git
synced 2024-12-19 21:27:52 +00:00
Review and integrate mobile-2008 (#2040)
Fixes #2008 * Viewport metatag updated * Fix to Time Conductor for Safari * Remove data visualization element in TC * Hide TC ticks when on mobile * Add touch functionality to mct-drag * Reduced size of image thumbnails; Changed min-heights of image and thumbnail holders for .mobile.phone * remove create dialog from mobile
This commit is contained in:
parent
e19ce4ac8c
commit
c909831dd4
11
index.html
11
index.html
@ -21,9 +21,10 @@
|
||||
-->
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title></title>
|
||||
<script src="bower_components/requirejs/require.js"> </script>
|
||||
<script>
|
||||
@ -79,10 +80,10 @@
|
||||
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="shortcut icon" href="platform/commonUI/general/res/images/favicons/favicon.ico">
|
||||
</head>
|
||||
<body class="user-environ">
|
||||
</head>
|
||||
<body>
|
||||
<div class="l-splash-holder s-splash-holder">
|
||||
<div class="l-splash s-splash"></div>
|
||||
</div>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -113,7 +113,8 @@ define([
|
||||
"agentService",
|
||||
"$window",
|
||||
"$location",
|
||||
"$attrs"
|
||||
"$attrs",
|
||||
"navigationService"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -24,14 +24,14 @@
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
var navigationListenerAdded = false;
|
||||
/**
|
||||
* Controller to provide the ability to show/hide the tree in
|
||||
* Browse mode.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/browse
|
||||
*/
|
||||
function PaneController($scope, agentService, $window, $location, $attrs) {
|
||||
function PaneController($scope, agentService, $window, $location, $attrs, navigationService) {
|
||||
var self = this;
|
||||
this.agentService = agentService;
|
||||
var hideParameterPresent = $location.search().hasOwnProperty($attrs.hideParameter);
|
||||
@ -61,6 +61,11 @@ define(
|
||||
self.state = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (navigationService && navigationService.addListener && !navigationListenerAdded) {
|
||||
navigationService.addListener(this.callback);
|
||||
navigationListenerAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -327,7 +327,8 @@ define([
|
||||
"key": "mctDrag",
|
||||
"implementation": MCTDrag,
|
||||
"depends": [
|
||||
"$document"
|
||||
"$document",
|
||||
"agentService"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ $tabularTdPadLR: $itemPadLR;
|
||||
$tabularTdPadTB: 2px;
|
||||
/*************** Imagery */
|
||||
$imageMainControlBarH: 25px;
|
||||
$imageThumbsD: 120px;
|
||||
$imageThumbsD: 100px;
|
||||
$imageThumbsWrapperH: 155px;
|
||||
$imageThumbPad: 1px;
|
||||
/*************** Ticks */
|
||||
|
@ -205,3 +205,14 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************** MOBILE */
|
||||
body.mobile.phone {
|
||||
.t-imagery {
|
||||
.l-image-main-wrapper,
|
||||
.l-image-thumbs-wrapper {
|
||||
//background: red;
|
||||
min-height: 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ body.mobile {
|
||||
}
|
||||
|
||||
.pane.right.items {
|
||||
//@include test();
|
||||
@include slMenuTransitions;
|
||||
left: 0 !important;
|
||||
margin-left: 0 !important;
|
||||
.holder-object-and-inspector {
|
||||
@include slMenuTransitions;
|
||||
@ -47,12 +47,10 @@ body.mobile {
|
||||
right: $bodyMargin !important;
|
||||
}
|
||||
|
||||
// When the tree is hidden, these are the
|
||||
// classes used for the left menu and the
|
||||
// right representation.
|
||||
// Assume landscape layout or either orientation for tablet
|
||||
// Phone portrait overrides below via media query
|
||||
.pane-tree-hidden {
|
||||
// Sets the left tree menu when the tree
|
||||
// is hidden.
|
||||
// Sets the left tree menu when the tree is hidden.
|
||||
.pane.left.treeview {
|
||||
@include trans-prop-nice(opacity, 150ms);
|
||||
opacity: 0 !important;
|
||||
@ -73,12 +71,12 @@ body.mobile {
|
||||
.pane.left.treeview {
|
||||
@include trans-prop-nice(opacity, 250ms, $delay: 250ms);
|
||||
@include background-image(linear-gradient(90deg, rgba(black, 0) 98%, rgba(black, 0.3) 100%));
|
||||
right: auto !important;
|
||||
width: $proporMenuWithView !important;
|
||||
right: auto !important;
|
||||
}
|
||||
// Sets the right representation when the tree is shown.
|
||||
.pane.right.items {
|
||||
left: $proporMenuWithView !important;
|
||||
transform: translateX($proporMenuWithView);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,12 +90,19 @@ body.mobile {
|
||||
}
|
||||
|
||||
.object-browse-bar {
|
||||
&.t-primary { margin-left: 45px; }
|
||||
&.t-primary {
|
||||
margin-left: 45px;
|
||||
|
||||
.title-label {
|
||||
// Prevent inline editing of the object title in the main view in mobile
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.context-available {
|
||||
font-size: 0.9em;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
.view-switcher {
|
||||
margin-right: 0 !important;
|
||||
.title-label {
|
||||
// Hide the name in mobile
|
||||
display: none;
|
||||
@ -131,19 +136,20 @@ body.mobile {
|
||||
}
|
||||
}
|
||||
|
||||
body.phone.portrait {
|
||||
@media only screen and (max-device-width: $phoMaxW) and (orientation: portrait) {
|
||||
body.mobile {
|
||||
.pane-tree-showing {
|
||||
.pane.left.treeview {
|
||||
width: $proporMenuOnly !important;
|
||||
}
|
||||
.pane.right.items {
|
||||
left: 0 !important;
|
||||
transform: translateX($proporMenuOnly);
|
||||
.holder-object-and-inspector {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.desktop {
|
||||
|
@ -28,7 +28,8 @@ $output-bourbon-deprecation-warnings: false;
|
||||
}
|
||||
|
||||
body, html {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.l-splash-holder {
|
||||
|
@ -20,6 +20,7 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
.user-environ,
|
||||
.browse-area,
|
||||
.edit-area,
|
||||
.editor {
|
||||
@ -47,6 +48,9 @@
|
||||
}
|
||||
|
||||
.user-environ {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden !important;
|
||||
.browse-area,
|
||||
.editor {
|
||||
top: 0; left: 0; right: 0; bottom: $ueFooterH;
|
||||
|
@ -46,7 +46,7 @@ define(
|
||||
* @constructor
|
||||
*
|
||||
*/
|
||||
function MCTDrag($document) {
|
||||
function MCTDrag($document, agentService) {
|
||||
|
||||
// Link; install event handlers.
|
||||
function link(scope, element, attrs) {
|
||||
@ -55,10 +55,26 @@ define(
|
||||
// only be attached to the element being linked, as the
|
||||
// mouse may leave this element during the drag.
|
||||
var body = $document.find('body'),
|
||||
isMobile = agentService.isMobile(),
|
||||
touchEvents,
|
||||
initialPosition,
|
||||
$event,
|
||||
delta;
|
||||
|
||||
if (isMobile) {
|
||||
touchEvents = {
|
||||
start: 'touchstart',
|
||||
end: 'touchend',
|
||||
move: 'touchmove'
|
||||
};
|
||||
} else {
|
||||
touchEvents = {
|
||||
start: 'mousedown',
|
||||
end: "mouseup",
|
||||
move: "mousemove"
|
||||
};
|
||||
}
|
||||
|
||||
// Utility function to cause evaluation of mctDrag,
|
||||
// mctDragUp, etc
|
||||
function fireListener(name) {
|
||||
@ -103,8 +119,8 @@ define(
|
||||
// Called only when the drag ends (on mouseup)
|
||||
function endDrag(event) {
|
||||
// Detach event handlers
|
||||
body.off("mouseup", endDrag);
|
||||
body.off("mousemove", continueDrag);
|
||||
body.off(touchEvents.end, endDrag);
|
||||
body.off(touchEvents.move, continueDrag);
|
||||
|
||||
// Also call continueDrag, to fire mctDrag
|
||||
// and do its usual position update
|
||||
@ -125,8 +141,8 @@ define(
|
||||
// Listen for mouse events at the body level,
|
||||
// since the mouse may leave the element during
|
||||
// the drag.
|
||||
body.on("mouseup", endDrag);
|
||||
body.on("mousemove", continueDrag);
|
||||
body.on(touchEvents.end, endDrag);
|
||||
body.on(touchEvents.move, continueDrag);
|
||||
|
||||
// Set an initial position
|
||||
updatePosition(event);
|
||||
@ -141,8 +157,8 @@ define(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Listen for mousedown on the element
|
||||
element.on("mousedown", startDrag);
|
||||
// Listen for start event on the element
|
||||
element.on(touchEvents.start, startDrag);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -26,8 +26,9 @@ define(
|
||||
|
||||
var JQLITE_METHODS = ["on", "off", "find"];
|
||||
|
||||
describe("The mct-drag directive", function () {
|
||||
describe("The mct-drag directive in Mobile", function () {
|
||||
var mockDocument,
|
||||
mockAgentService,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
@ -45,6 +46,8 @@ define(
|
||||
beforeEach(function () {
|
||||
mockDocument =
|
||||
jasmine.createSpyObj("$document", JQLITE_METHODS);
|
||||
mockAgentService =
|
||||
jasmine.createSpyObj("agentService", ["isMobile"]);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", ["$eval", "$apply"]);
|
||||
mockElement =
|
||||
@ -59,8 +62,137 @@ define(
|
||||
};
|
||||
|
||||
mockDocument.find.andReturn(mockBody);
|
||||
mockAgentService.isMobile.andReturn(true);
|
||||
|
||||
mctDrag = new MCTDrag(mockDocument);
|
||||
mctDrag = new MCTDrag(mockDocument, mockAgentService);
|
||||
mctDrag.link(mockScope, mockElement, testAttrs);
|
||||
});
|
||||
|
||||
it("is valid as an attribute", function () {
|
||||
expect(mctDrag.restrict).toEqual("A");
|
||||
});
|
||||
|
||||
it("listens for touchstart on its element", function () {
|
||||
expect(mockElement.on).toHaveBeenCalledWith(
|
||||
"touchstart",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
// Verify no interactions with body as well
|
||||
expect(mockBody.on).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("invokes mctDragDown when dragging begins", function () {
|
||||
var event = testEvent(42, 60);
|
||||
mockElement.on.mostRecentCall.args[1](event);
|
||||
expect(mockScope.$eval).toHaveBeenCalledWith(
|
||||
testAttrs.mctDragDown,
|
||||
{ delta: [0, 0], $event: event }
|
||||
);
|
||||
});
|
||||
|
||||
it("listens for touchmove after dragging begins", function () {
|
||||
mockElement.on.mostRecentCall.args[1](testEvent(42, 60));
|
||||
expect(mockBody.on).toHaveBeenCalledWith(
|
||||
"touchmove",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
expect(mockBody.on).toHaveBeenCalledWith(
|
||||
"touchend",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("invokes mctDrag expression during drag", function () {
|
||||
var event;
|
||||
|
||||
mockElement.on.mostRecentCall.args[1](testEvent(42, 60));
|
||||
|
||||
// Find and invoke the touchmove listener
|
||||
mockBody.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === 'touchmove') {
|
||||
call.args[1](event = testEvent(52, 200));
|
||||
}
|
||||
});
|
||||
|
||||
// Should have passed that delta to mct-drag expression
|
||||
expect(mockScope.$eval).toHaveBeenCalledWith(
|
||||
testAttrs.mctDrag,
|
||||
{ delta: [10, 140], $event: event }
|
||||
);
|
||||
});
|
||||
|
||||
it("invokes mctDragUp expression after drag", function () {
|
||||
var event;
|
||||
|
||||
mockElement.on.mostRecentCall.args[1](testEvent(42, 60));
|
||||
|
||||
// Find and invoke the touchmove listener
|
||||
mockBody.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === 'touchmove') {
|
||||
call.args[1](testEvent(52, 200));
|
||||
}
|
||||
});
|
||||
// Find and invoke the touchmove listener
|
||||
mockBody.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === 'touchend') {
|
||||
call.args[1](event = testEvent(40, 71));
|
||||
}
|
||||
});
|
||||
|
||||
// Should have passed that delta to mct-drag-up expression
|
||||
// and that delta should have been relative to the
|
||||
// initial position
|
||||
expect(mockScope.$eval).toHaveBeenCalledWith(
|
||||
testAttrs.mctDragUp,
|
||||
{ delta: [-2, 11], $event: event }
|
||||
);
|
||||
|
||||
// Should also have unregistered listeners
|
||||
expect(mockBody.off).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("The mct-drag directive in Desktop", function () {
|
||||
var mockDocument,
|
||||
mockAgentService,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockBody,
|
||||
mctDrag;
|
||||
|
||||
function testEvent(x, y) {
|
||||
return {
|
||||
pageX: x,
|
||||
pageY: y,
|
||||
preventDefault: jasmine.createSpy("preventDefault")
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockDocument =
|
||||
jasmine.createSpyObj("$document", JQLITE_METHODS);
|
||||
mockAgentService =
|
||||
jasmine.createSpyObj("agentService", ["isMobile"]);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", ["$eval", "$apply"]);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", JQLITE_METHODS);
|
||||
mockBody =
|
||||
jasmine.createSpyObj("body", JQLITE_METHODS);
|
||||
|
||||
testAttrs = {
|
||||
mctDragDown: "starting a drag",
|
||||
mctDrag: "continuing a drag",
|
||||
mctDragUp: "ending a drag"
|
||||
};
|
||||
|
||||
mockDocument.find.andReturn(mockBody);
|
||||
mockAgentService.isMobile.andReturn(false);
|
||||
|
||||
mctDrag = new MCTDrag(mockDocument, mockAgentService);
|
||||
mctDrag.link(mockScope, mockElement, testAttrs);
|
||||
});
|
||||
|
||||
|
@ -44,11 +44,26 @@ define(
|
||||
*/
|
||||
function MobileClassifier(agentService, $document) {
|
||||
var body = $document.find('body');
|
||||
Object.keys(DeviceMatchers).forEach(function (key) {
|
||||
|
||||
Object.keys(DeviceMatchers).forEach(function (key, index, array) {
|
||||
if (DeviceMatchers[key](agentService)) {
|
||||
body.addClass(key);
|
||||
}
|
||||
});
|
||||
|
||||
if (agentService.isMobile()) {
|
||||
var mediaQuery = window.matchMedia('(orientation: landscape)');
|
||||
|
||||
mediaQuery.addListener(function (event) {
|
||||
if (event.matches) {
|
||||
body.removeClass('portrait');
|
||||
body.addClass('landscape');
|
||||
} else {
|
||||
body.removeClass('landscape');
|
||||
body.addClass('portrait');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return MobileClassifier;
|
||||
|
@ -145,14 +145,14 @@
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
&.start-w {
|
||||
@include background-image(linear-gradient(270deg, transparent, $wBgColor $ticksBlockerFadeW));
|
||||
@include background-image(linear-gradient(270deg, rgba($wBgColor,0), rgba($wBgColor,1) $ticksBlockerFadeW));
|
||||
padding-right: $ticksBlockerFadeW;
|
||||
.title:before {
|
||||
content: 'Start';
|
||||
}
|
||||
}
|
||||
&.end-w {
|
||||
@include background-image(linear-gradient(90deg, transparent, $wBgColor $ticksBlockerFadeW));
|
||||
@include background-image(linear-gradient(90deg, rgba($wBgColor,0), rgba($wBgColor,1) $ticksBlockerFadeW));
|
||||
padding-left: $ticksBlockerFadeW;
|
||||
right: 0;
|
||||
.title:before {
|
||||
|
@ -79,12 +79,9 @@
|
||||
|
||||
<input type="submit" class="off">
|
||||
</form>
|
||||
<conductor-axis view-service="tcController.conductorViewService"></conductor-axis>
|
||||
<conductor-axis class="mobile-hide" view-service="tcController.conductorViewService"></conductor-axis>
|
||||
</div>
|
||||
|
||||
<!-- Holds data visualization, time of interest -->
|
||||
<conductor-toi view-service="tcController.conductorViewService"></conductor-toi>
|
||||
|
||||
<!-- Holds time system and session selectors, and zoom control -->
|
||||
<div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem">
|
||||
<mct-include
|
||||
|
@ -199,12 +199,6 @@
|
||||
|
||||
&.l-pane-r {
|
||||
left: 0;
|
||||
&:hover {
|
||||
.l-hover-btns-holder {
|
||||
@include trans-prop-nice-fade(100ms);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.l-pane-top {
|
||||
@ -246,8 +240,6 @@
|
||||
.l-hover-btns-holder {
|
||||
@include absPosDefault();
|
||||
box-sizing: border-box;
|
||||
@include trans-prop-nice-fade(500ms);
|
||||
opacity: 0;
|
||||
height: $timelineTopPaneHeaderH;
|
||||
left: auto;
|
||||
padding: $interiorMargin $interiorMargin $interiorMargin $interiorMargin * 10;
|
||||
|
@ -41,6 +41,7 @@ define(
|
||||
*/
|
||||
function ContextMenuGesture($timeout, agentService, element, domainObject) {
|
||||
var isPressing,
|
||||
isDragging,
|
||||
longTouchTime = 500;
|
||||
|
||||
function showMenu(event) {
|
||||
@ -67,16 +68,22 @@ define(
|
||||
// After the timeout, if 'isPressing' is
|
||||
// true, display context menu for object
|
||||
$timeout(function () {
|
||||
if (isPressing) {
|
||||
if (isPressing && !isDragging) {
|
||||
showMenu(event);
|
||||
}
|
||||
}, longTouchTime);
|
||||
}
|
||||
});
|
||||
|
||||
// Whenever the touch event ends, 'isPressing' is false.
|
||||
// If on Mobile Device, and user scrolls/drags set flag to true
|
||||
element.on('touchmove', function () {
|
||||
isDragging = true;
|
||||
});
|
||||
|
||||
// Whenever the touch event ends, 'isPressing' & 'isDragging' is false.
|
||||
element.on('touchend', function () {
|
||||
isPressing = false;
|
||||
isDragging = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user