Compare commits

...

215 Commits

Author SHA1 Message Date
8072e829ad [Mobile] Comments
Added comments to plot controller
regarding the change in the snapping
to right and mobile adjustment.
2015-09-03 16:30:12 -07:00
e866ddb9fd [Mobile] Plot & Gestures
Plot adjusted so that when snapping to the right
the left domain value also moves same amount that
the right domain did. Also Interval between left
and right domains on screen are dyanmically set to
amount zoomed in/out, instead of being defaulted
to 2 minutes. Made small edit to display if the chart
has been manipulated (panned or zoomed) or is updating
live.
2015-09-03 16:15:34 -07:00
4fa29d30f5 [Mobile] Gestures
Distance change to differentiate between
pan and pinch increased from 2 to 3.
2015-09-03 11:48:42 -07:00
c394151c46 [Mobile] Gestures
Redraw rate adjusted to redraw on
mobile every 15ms instead of 1000ms
(like on desktop). Also added agentservice
to PlotController and MCTChart (bundles and

file.
2015-09-03 11:47:33 -07:00
db1b76413c [Mobile] Clean Up
Removed test PlotController functions
which are unused.
2015-09-03 09:53:17 -07:00
c8b02d355f [Mobile] Comments
Clarifies what the ratio is for the
distance.
2015-09-03 09:51:12 -07:00
7c110ee8af [Mobile] Gestures
Removed plot.html mct-pinch reference
because it was not being used. Also
adjusted MCTPlot comment.
2015-09-03 09:21:10 -07:00
49213f550f [Mobile] Comments
Commented on the trackTouchPosition
addition.
2015-09-03 09:08:47 -07:00
447ae3f20b [Mobile] Comments
Added comments to the MCTPinch file.
2015-09-02 13:44:17 -07:00
7288db1908 [Mobile] Comments
Added comments to the MCTPinch file.
2015-09-02 13:37:17 -07:00
908fbdbf73 [Mobile] Clean Up
Changed one line space.
2015-09-02 12:59:44 -07:00
052a359738 [Mobile] Comments
Added comments to the MCTPinch file.
2015-09-02 12:58:56 -07:00
f9be00a70f [Mobile] Clean Up
Reorganizaed MCTPlot touch
functions to be in suitable order. Also
made code DRYer by removing unnecessary functions
and combining statements that are used once. Also
renamed variables to differentiate similar ones
from one another. Added marks to show where
comments are needed (will be edited in next
commit).
2015-09-02 12:45:52 -07:00
d1055f0839 [Mobile] Refactor
Refactored calculateViewport
to use ratio to cacluate the sign of
required zoom in or zoom out, and then
apply that to the ZOOM_AMT. Makes function
DRYer.
2015-09-02 11:23:33 -07:00
0b7ab75512 [Mobile] Comments
Added comments to destroy and remaining
MCTPinch functions.
2015-09-02 10:20:49 -07:00
9d1841db55 [Mobile] Adjust pan/pinch check
Now check done for pan/pinch using
variables set during start of gesture.
Also added functions to touch amount
checks to make MCTPinch DRYer. Comments
regarding touch functions and added
variables/functions.
2015-09-02 10:18:40 -07:00
50d10639e1 [Mobile] Clean Up
Changed variable placement
for amount of distance changed allowed
for a pinch drag.
2015-09-02 09:23:25 -07:00
5a9619ce26 [Mobile] Clean Up
Removed unneeded variables passed into
MCTPlot functions.
2015-09-02 09:16:01 -07:00
42b7427816 [Mobile] Clean up
Renamed the setDR to be set
Dimensions. Also removed unneeded
calculateDistance function.
2015-09-02 09:14:54 -07:00
a1b37b1269 [Mobile] Clean Up
Added comments and cleaned up a bit
of the MCTPinch file.
2015-09-02 09:13:28 -07:00
c8ca1deb9b [Mobile] Gestures
Fixed the range of values for
differentiating between pan and
pinch zoom to not assign the +2/-2
value to the variable.
2015-09-01 12:15:48 -07:00
5be6e90388 [Mobile] Clean Up
Commented out console calls from gesture
pinch/plot classes. Also allowed pan with
single finger.
2015-09-01 11:53:41 -07:00
814b04858a [Mobile] Gestures
MCTPinch adjusted the touch check to help
differentiate between a two finger touch
vs a single singer pan.
2015-09-01 11:45:11 -07:00
aedbd3bd9b [Mobile] Gestures
ZOOM_AMT set back to original
0.02, because .025 made zoom out
too fast.
2015-09-01 10:45:02 -07:00
aa4dbf7062 [Mobile] Gestures
Ratio used to check if
zoom should be in or out now
divides lastDistance/distance
instead of firstDistance/distance.
Therefore by comparing last distance,
user is able to zoom in and out on
same pinch without removing fingers.
2015-09-01 10:24:32 -07:00
5b95574673 [Mobile] Gestures
Slight adjustment to the ZOOM_AMT,
increased by .005 from .02 to .025.
2015-09-01 10:22:02 -07:00
2295be5e35 [Mobile] Gestures
Set the range of difference allowed between
the last distance and current distance to
differenciate panning and zooming. If
lastDistance - 2 <= currentDistance <= lastDistance + 2
than panning occurs, otherwise user is zooming.
BUG: The auto snap to right side of chart causes the
chart to resize narrower overtime and as user BOTH
zooms and pans more.
2015-09-01 10:17:53 -07:00
0ac6caa823 [Mobile] Gestures
Added a zoom amount variable
that is set at top of MCTPlot.
Sets the amount of zoom multiplier.
2015-09-01 10:14:51 -07:00
5e1dd04e6d [Mobile] Pinch & Pan
Adjusted Pinch to check if
distance between 2 fingers
(rounded to whole number) is equal to
last distance or first distance, if this
is true, than will pan otherwise do
pinch zoom.
2015-08-31 16:25:44 -07:00
29df378851 [Mobile] Gestures
Removed firstTouchPan and use
firstTouch for both the pinch and the
single touch pan.
2015-08-31 16:22:43 -07:00
8511c957a0 [Mobile] Gestures
Adjusted the 0.03 'multiplier'
from 0.01, to allow faster zooming in
and out.
2015-08-31 15:48:11 -07:00
f4efc79539 [Mobile] Clean up
Removed call to console.
2015-08-31 15:47:19 -07:00
3926d6f617 [Mobile] Gesture
Zooms in at 0.01 amount (like last commit)
however the pinch's midpoint is the center
point at which the zoom focuses on.
2015-08-31 15:33:33 -07:00
d65e0f820f [Mobile] Gestures
Currently zooms into center by narrowing each
dimension by 0.01
2015-08-31 14:47:02 -07:00
24fe419be4 [Mobile] Gestures
Slight clean up to MCTPinch.
2015-08-31 13:01:15 -07:00
3e2c3f913b [Mobile] Gesture Check
Commented out panand trackes current 2
touches on pinch.
2015-08-28 16:48:54 -07:00
a45b09277e [Mobile} Pan/Pinch
Cleaned up the variables.
2015-08-28 16:01:00 -07:00
bdf3e4d8a3 [Mobile] Pan/Pinch
On destoying the scope of
MCTPinch, all the listeners for
touch events on the element are
destroyed.
2015-08-28 15:39:16 -07:00
e4a2904213 [Mobile] Pan Gesture
Added pan gesture functionality
with one finger to MCTPlot.
2015-08-28 15:23:19 -07:00
f1d4e36c02 [Mobile] Gestures
Added an endTouch/Zoom to the
MCTPlot to mark when the user
has canceled/ended their touch
event.
2015-08-28 15:22:15 -07:00
b3792c21be [Mobile] Gestures
Adjusted MCTPinch names to work
for both pan and pinch.
2015-08-28 15:20:46 -07:00
1fbbf355f4 [Mobile Gestures] Pan
Adds pan gesture to plots. Sets up the
zoom gesture addition. Also the back button
is visible on desktop versions.
2015-08-20 11:26:09 -07:00
9fec73da14 Merge remote-tracking branch 'upstream/plot-vee-two' into mobile_gestures_1 2015-08-17 13:20:02 -07:00
23048f0df9 [Mobile Gestures] Comments
Added comments to pinch functions.
2015-08-17 13:15:46 -07:00
dfe3409a98 [Mobile, Gestures] Pinch
Split the pinch gesture into start,
change, and end/cancel. Each of those
are read in and then they emit through
the scope to functions in the controller.
2015-08-17 13:12:53 -07:00
5c3fe78bd5 [Mobile, Gestures] Pinch
Moved MCTPinch directive into
plot-reborn. Now emits on pinch action
the event to the controller. Edited plot.html
to clean up and edited mct-plot.html to
include mct-pinch. DrawLoader adjusted to
allow  and prevent error.
2015-08-17 12:51:33 -07:00
eb69e02ce3 [Plot] Reset telemetry objects on change 2015-08-17 12:39:38 -07:00
17e2da2d2c Merge remote-tracking branch 'upstream/plot-vee-two' into mobile_gestures_1 2015-08-17 10:53:54 -07:00
03db1b3623 Merge remote-tracking branch 'upstream/master' into mobile_3 2015-08-17 10:51:28 -07:00
5c23daa5ff [Mobile, Gestures] Pinch
Pinch directive commited with removal
of gestures. Added connection to controller
and plot application on html file.
2015-08-17 10:49:11 -07:00
056b3f61ce [Style] JSLint Compliance 2015-08-14 11:54:46 -07:00
a0dc3da8fb [Plot] Use ColorService for plot colors 2015-08-13 16:07:08 -07:00
48f345a46b [Service] ColorPalette is now ColorService 2015-08-13 16:06:26 -07:00
2cf7f6794c Merge remote-tracking branch 'upstream/master' into mobile_3 2015-08-13 09:14:28 -07:00
889a5c6ea9 Allow duplicates in repeats, use proper labels 2015-08-12 16:50:51 -07:00
5502009127 Reasonable defaults for directive scope 2015-08-12 16:50:09 -07:00
cb41be7922 Plot uses ColorPalette to allocate colors 2015-08-12 16:27:28 -07:00
2997f2a261 [Mobile, Gestures] Removed Gesutres
Removed gesture info from bundles,
switching to using directives for
pinch.
2015-08-12 16:22:04 -07:00
52b8720d37 ColorPalette dispenses colors. 2015-08-12 16:17:20 -07:00
bb8c8a75ab MCTChart preserves precision of plot values 2015-08-12 13:59:32 -07:00
d10c56f732 Merge remote-tracking branch 'upstream/master' into mobile_3 2015-08-12 09:27:02 -07:00
1f7d0427b7 [Mobile, Gestures] Clean Up
Moved one file, push/pan still
applied to whole pane.
2015-08-11 12:13:43 -07:00
caf1e3aea9 [Mobile, Gestures] Tests
Adjusted tests to call to correct
firedGesture.
2015-08-11 10:57:52 -07:00
3031579a62 [Mobile] Gestures
Started gesture implementation for
representation panes. Currently added Pan
and Pinch Gesture js, where the PanGesture
tracks single finger movement. PinchGesture
tracks the distance between two fingers. Also
added test spec files that test without error
but are incomplete. Current issue is that
pinch and pan gestures are applied to the entire
right pane, which includes header. Need to target
only representation of the right pane.
2015-08-10 11:31:33 -07:00
00aa7ce0c2 [Mobile, Gestures] Pinch/Pan
Made unbind call more DRY.
2015-08-07 14:52:23 -07:00
cac97401c6 [Mobile, Gestures] Pan/Pinch
Added Destroy return function that
.off all touch events on elements.
And unbinds touch events from element.
2015-08-07 14:26:23 -07:00
7b371327e6 [Mobile, Gestures] Pan
Added pan file which is based on
PinchGesture. Also made PinchGesture more
DRY. PanGesture, like PinchGesture only
logs the pan coordinates on touch moving.
Added check to pinch and pan to disallow those
gestures in folder representations.
2015-08-07 14:16:32 -07:00
113d1c909f [Mobile, Gestures] Pinch
Pinch gesture being implemented.
Currently tracks two touchChanges
that track location and find distance
between them. Logs the distances currently.
2015-08-07 12:20:57 -07:00
7ca15a9de2 [Mobile] Representation
Edited grid item to center
shared button.
2015-08-06 14:11:59 -07:00
dcd7d61c9a [Mobile] Tests
Completed ContextMenu and InfoButton
Gesture tests where elements/body
touch events occur.
2015-08-06 13:43:56 -07:00
0a39984c4f [Mobile] Clean Up
Fixed InfoService having 0 in
wrong spot. Also correctly compared
the UserAgent device to iPhone for
isMobile function in AgentService.
2015-08-05 12:26:09 -07:00
0b635afcf7 [Mobile] Tests
ContextMenu and InfoButton Gesture
tests remain.
2015-08-05 12:14:16 -07:00
f46a0853b9 [Mobile] Tests
Removed mockMenu from ContextMenuGestureSpec.
2015-08-04 16:58:37 -07:00
6b65ae77e7 [Mobile] Tests
Completed tests for AgentService,
InfoService, and ContextMenuAction.
ContextMenu and InfoButton Gesture
tests remain. Also resized info button
icon.
2015-08-04 16:48:41 -07:00
66408eeec8 [Mobile] Gestures
Now to dismiss bubble, touch anywhere
the touch will not fire other gestures
(such as the pressing of another object).
2015-08-04 13:41:48 -07:00
3d524d7572 [Mobile] AgentService
Replaced name queryService with agentService.
2015-08-04 10:11:25 -07:00
9b922913a0 [Mobile] Gestures
Added styling to back and selection
arrow (tree). Also increased the space
allowed for selection arrow on tree item.
Info Button created on grid items for mobile.
Info bubble appears on tablet like desktop.
Also on mobile, info bubble fits to width.
New QueryService that returns if on iPhone.
Also formatted dialog box so that their is no
margin and takes up fullscreen on mobile.
2015-08-04 09:59:08 -07:00
560a2e035e [Mobile] Info Button
Added info button to grid/list items
on mobile. When the button is pressed,
info bubble appears for 750ms or the
same infobutton is pressed to dismiss
immediately.
2015-07-31 11:13:52 -07:00
eca52a8ca6 Merge remote-tracking branch 'upstream/master' into mobile_3 2015-07-31 09:09:31 -07:00
25e8bb44d2 [Mobile] Item Height
Adjusted item height in
folder/layout list to be
automatically same as the
list object, not flowing over.
Applied to both phones and tablets.
2015-07-30 14:10:43 -07:00
85658d3d1f [Mobile] Tests
Removed tests causing incomplete
build.
2015-07-30 13:33:59 -07:00
ddce0f371d [Mobile] Test
Removed extra mockEvent from test.
2015-07-30 13:32:24 -07:00
495cd06ed5 [Mobile] Tests
adjusted test to fill empty
functions.
2015-07-30 13:30:03 -07:00
1624866656 [Mobile/Bug] RemoveAction
When removing object you have
openned, now compares the currentObj
id with the removed obj id, resulting
in navigating to parent if they are the
same.
2015-07-30 13:27:56 -07:00
2d1aa65d63 [Mobile] Test
BrowseController test adjusted to
repeat less code.
2015-07-30 12:50:39 -07:00
c333a2e70a [Mobile] Test
Repeat of test variable deleted.
2015-07-29 16:31:38 -07:00
906354764b [Mobile] Tests
Has way to make isMobile call
true or false for mobile/nonmobile
devices.
2015-07-29 15:06:39 -07:00
12ec293f3d [Mobile] Tests
Changed BrowseController and RemoveActionSpec to account
for grandparent and navigation usage. Also changed
RemoveAction variable name.
2015-07-29 13:57:11 -07:00
bdf8b4d3f1 [Mobile] Test for Back Arrow
Added tests for the backarrow and
when it appears/disappears.
2015-07-29 13:22:47 -07:00
6e60088b11 [Mobile] RemoveAction
Removed console and added
navigationService (mock) to the
spec version.
2015-07-29 11:58:53 -07:00
97bf530b1d [Mobile] BackArrow
Removed the BackArrow console log
that was getting called in the
BrowseController.
2015-07-29 11:41:10 -07:00
18348476c6 [Mobile] RemoveAction Tweak
If you remove an object you are
currently within/opened, then on
removal of it you navigate to the
parent of whatever you removed.
2015-07-29 11:38:47 -07:00
7e35e55f0b [Mobile] Hide Back Button
When you are at the highest level the
back button fades out and is unclickable.
When you are able to go up a level the
back button appears/fades in and is
pressable. Also removed the object type
name from the header.
2015-07-29 11:13:09 -07:00
28a2a5b92a [Mobile] Tweaks to layout
Removed the user-select option
for the context menu and bottom bar
on mobile. Also edited the folder
grid item so that its icon rep
size is not overly large.
2015-07-29 10:39:17 -07:00
d262520594 [Mobile] Tree menu Open
Tree menu select arrow button's width
is now size of full button. Prior to this
the pressable area was less and therefore
less responsive.
2015-07-29 10:25:09 -07:00
7cc14a195b [Mobile] Tests/Header
Removes back arrow on desktops.
Also added queryService to tests
for the context menu action and
gesture.
2015-07-29 10:00:03 -07:00
84b9e4d781 [Mobile] Context Menu
Context menu next to object header
now dismisses when touching away
from it. Also, when long touching
an object, the context menu appears.
Set on 500ms timeout.
2015-07-28 17:09:15 -07:00
356fa73c91 [Mobile] Tests
Test created for backArrow
that spies on all objects
used to find parent.
2015-07-28 15:55:22 -07:00
a073ef69ac [Mobile] Back Arrow
Shifted Back Arrow down to
align with header.
2015-07-28 15:15:42 -07:00
3c6c420023 [Mobile] Back Arrow
Back Arrow implemented
by getting parent and then
navigating to it.
2015-07-28 15:08:14 -07:00
2a4943f584 [Mobile] Console
Removed call to console so
mvn clean install would compile.
2015-07-28 10:58:22 -07:00
e32403a75f [Mobile] Clean-Up
Cleaned the unused code for the
backArrow and long touch gestures.
Commented out functions for later use
Currently shows the back arrow, however,
only will print to console on press.
Edited tests where mobile checks were breaking
and fixed.
2015-07-28 10:56:29 -07:00
b0c42c12b7 [Mobile] Back Arrow
Changes URL correctly that
is printed to the console. Is the
url to up one level of objects.
However not navigating to that
object.
2015-07-27 17:01:30 -07:00
621ccc25ec [Mobile] Back Arrow HTML
Created HTMl for back arrow,
next neew to hook up a click.
2015-07-27 15:31:47 -07:00
617df739ee [Mobile] persistence
Removed elasticsearch.
2015-07-27 15:26:09 -07:00
6e43a92191 [Mobile] Merge
Fix Conflicts.
2015-07-27 15:21:59 -07:00
a9418fd2c7 Merge remote-tracking branch 'upstream/master' 2015-07-27 11:32:41 -07:00
1d7a0fa48d [Mobile] Removed InfoGesture
Commented out infogesture.
2015-07-27 11:30:29 -07:00
30c530178a [Mobile] No ContextMenu
Removed context menu code
started to be used for the
long hold gesture.
2015-07-27 11:01:03 -07:00
3d0795cde3 [Mobile] Starting Context
Added check to make sure
user is touching only one object.
Started contextmenugesture to be
long touch, however currently long
touch is still infogesture.
2015-07-27 10:20:08 -07:00
c85a3787c0 [Mobile] User-Select
Edited user-select used in
panes' layout to only
happen on phones and tablets
(just to be safe).
2015-07-24 16:46:45 -07:00
066258ab83 [Mobile] User-Select
Removes the copy/define
mobile safari menu that
appears during some touch events.
Only apply to left and right panes.
2015-07-24 16:19:15 -07:00
ddc2295ec3 [Mobile] Touch Hold Gesture
Rough touch hold gesture added
to the info gesture. Currently
if you hold on an item (that you
would normally hover over) for
500ms, you get the info gesture pop
up.
2015-07-24 16:02:06 -07:00
011e6fc512 [Mobile] Clean Up
Moved Mobile check in InfoGesture to
call on mouseEnter.
2015-07-24 15:27:33 -07:00
91bd58215a [Mobile] Size Adjustment
Moved hamburger icon slightly up
using the padding instead of
margin.
2015-07-24 12:38:01 -07:00
b37ee19fbc [Mobile] Size Adjustment
Adjusted indentation size
on the tree. Also change size of the
hamburger icon to match the
object icon and moved it slightly
down.
2015-07-24 12:35:19 -07:00
2355d354b3 [Mobile] Items List
Flushes items left and
vertically centers the
title/details. Also cleaned
up the items classes in sass
files.
2015-07-24 11:46:58 -07:00
200c6e49fc [Mobile] Test
QueryService (mock) added to the
ContextMenuGestureSpec to account
for isMobile call that allows/
disallows use of contextmenu
gesture.
2015-07-23 16:55:45 -07:00
a89f9eed42 [Mobile] Grid List/Gestures
Context menu only shown with contextmenu
click on desktops (non-mobile devices). Also
edited items list in a folder's representation
to show the icon on the left side, with text
centered horizontally (only mobile).
2015-07-23 16:47:57 -07:00
7993e4c03f [Mobile] Gestures
Removed the hover coloring on
the tree menu on mobile by changing
original** scss code. Also added
check in ContextMenuGesture that
will only allow context menu to appear
in non-mobile browser.
2015-07-23 15:01:14 -07:00
b592b89dc8 [Mobile] Clean Up
Removed unnecessary transitions.:
2015-07-23 14:15:01 -07:00
d115166dde [Mobile] Comments
Added comments and removed
unwanted spec test code for
BrowseController.
2015-07-23 13:48:21 -07:00
d176f9f811 [Mobile] Test
Fixed BrowseControllerSpec.js to
account for the .treeslide
call and added a new test for thatasds
2015-07-23 13:46:46 -07:00
143e3eeb6c [Mobile] CleanUp/Tests
Added tests inside spec files
for the QueryService, TreeNodeController,
and InfoGesture. Also cleaned up the
tree so that padding is used between
buttons instead of margins.
2015-07-23 13:19:58 -07:00
50ce800c2a Merge branch 'master' of https://github.com/shivamndave/openmctweb 2015-07-23 09:51:33 -07:00
1a1eecb4c3 Merge remote-tracking branch 'upstream/master' 2015-07-23 09:51:10 -07:00
b3bc8b6876 [Mobile[ Tests
Added jasmine test for

QUerySerivce and adjusted
the InfoGestureSpec to
account for use of
QueryService.
2015-07-23 09:28:36 -07:00
1f7ba70ad7 [Mobile] Scroll Bug
Removed scrollbar that appears in landscape
mode in tree menu.
2015-07-22 15:21:34 -07:00
7aba3b6672 [Mobile] Clean Up
Removed gap below bottom bar. Moved
around constants for the resizing
of the tree. Also added comments in
layout and reformatted that slightly.
2015-07-22 12:53:49 -07:00
926b3d075c [Mobile] Clean Up
Cleaned up scss files. Removed
repeated statements and added
comments. Also commented js files
like QueryService and InfoGesture.
2015-07-22 10:25:21 -07:00
827cb27f28 [Mobile] Menu
Added margin to top of tree list items.
Also removed hovering Info coming
up on mobile devices.
2015-07-21 16:19:59 -07:00
0842f464db [Mobile] Menu Adjustment
Makes highlight go all the way to right.
Also makes the arrow be absolute on the
right side, making it aligned to right.
2015-07-21 14:29:13 -07:00
56e51ea32a [Mobile] Reformat of menu
Reformats menu to move the
arrow to the right and now
that is what selects an object.
Pressing the actual menu item will
enact the dropdown menu. This
only happens on mobile platforms.
2015-07-21 13:29:45 -07:00
dcdafbaebf [Mobile] Fix Shift
Shifting occurring during transition
fixed by making transition backface-
visibility hidden during the
transition.
2015-07-20 10:25:27 -07:00
f98915cddd [Mobile] Comments
Added comments to the mixin list.
2015-07-20 09:51:37 -07:00
4e6c307684 [Mobile] Transition
Adjusts transition time on fade.
2015-07-20 09:48:12 -07:00
ce6d74390e [Mobile] Clean-Up
Removed unnecessary classes. Also added
comments and adjusted menu sizes.
2015-07-20 09:39:06 -07:00
6e406fd060 [Mobile] Right Pane sets
Right pane sets the size of itself,
causing the left pane to re-adjust
to fit the screen based on it. Also
transitions work on the slide and the
fade in.
2015-07-20 09:16:28 -07:00
2614427e0e [Mobile] Fix
Fixed to open menu fully.
2015-07-17 14:32:33 -07:00
272c6bca97 [Mobile] Create Menu
Create menu's is specified/overwritten
with 1000% (change) to fit on mobile).
Also gets rid of the right bar in that view.
2015-07-17 10:50:02 -07:00
0d7387080d [Mobile] Create Menu
Create menu text has ellipsis
attribute now, so if text is cut off
it will have a '...' appended to it.
Also added comments to mixins.
2015-07-17 10:28:19 -07:00
1e2e20b145 [Mobile] Comments
Added comments to the mixins.
2015-07-17 09:04:39 -07:00
488829a20c [Mobile] Header
Removed type from header
along with the right side buttons.
2015-07-16 16:13:58 -07:00
85c7a36e25 [Mobile] Cleaned up
Set the width of the create menu
text/components to fit the menu
however it gets cuttoff sometimes.
Next steps are to Clean up screen,
change the create menu to fit the left side,
and fix bottom space.
2015-07-16 15:21:17 -07:00
d99b4d75d8 [Mobile] Fix
Fixed the desktop version breaking.
CUrrent issue is hte menu is getting cut off.
2015-07-16 14:07:25 -07:00
15a88967d0 [Mobile] Transition/Create Fix
Fix the create button to work and
also transition well. Added transition mixin
to stay DRY.
2015-07-16 13:22:07 -07:00
6e6fbe0d65 [Mobile] Transitions
Made transitions properly work for
create button.
2015-07-16 12:54:10 -07:00
180e5f14ae [Mobile] Cleaned up
Made pane sass code more DRY by
using the phoneandtablet mixin
on repeated conditions.
2015-07-16 12:25:06 -07:00
e9314898d2 [Mobile] Portrait & Landsc.
Specifies amounts based on phone and tablet's
orientation. Not tested for the actual device,
but emulator. Also currently makes the create
button appear/disappear instead of smoothly sliding.
2015-07-16 11:50:55 -07:00
ce75d19480 [Mobile] Desktop
Cleans up the _layout by making the different
pane sizes device specific. Also adds a new
sass class just for desktop versions.
2015-07-16 10:44:20 -07:00
a9dd1f9828 [Mobile] Transistions
Cleaned up and added transitions.
2015-07-15 16:57:36 -07:00
4b5540830b [Mobile] Slide menu
Rouch menu using important to
overwrite splitter setting of
amounts. Also has default values
for now for all devices.
2015-07-15 16:49:16 -07:00
ee35976c92 [Mobile] Tree Mobile
Added mobile/_tree.scss and edited
normal tree.scss to accomodate for
future sass that adjusts the tree
menu.
2015-07-15 13:30:06 -07:00
54b6cd1100 [Mobile] Debug
Added debug statement to print
to console.
2015-07-15 13:28:42 -07:00
0f89e98a71 [Mobile] Clean up
Cleaned up layout and added phone only hider.
Also added tree.scss file, where all tree
node classes will be placed.
2015-07-14 14:14:12 -07:00
6f07a21bb8 [Mobile] Clean-up
Cleaned up scss and also, the
edit/new tab/full screen buttons are
hidden in mobile, temporarily.
2015-07-14 13:10:28 -07:00
f3678d9d52 Merge remote-tracking branch 'origin' into mobile_1 2015-07-14 13:08:54 -07:00
9a7bbd92bd [Mobile] Cleaned up
Cleaned up the transistion css to
be more DRY.
2015-07-13 17:04:14 -07:00
edcafc5835 [Mobile] Remove Bar
Remove the splitter bar on mobile
and tablets.
2015-07-13 13:56:44 -07:00
7d09df9a85 [Mobile] Constants
Re-edited media query constants
to be cleaner and consistent.
2015-07-13 13:11:27 -07:00
b00eee00fc [Mobile] Redefine
Renames variables to be clearer.
Breaks up constants into parts to be
cleaners and straightforward. Also
removed the ratio.
2015-07-13 13:02:57 -07:00
c0d83f9395 [Mobile] Format
Reformatted the rwd media
query rules.
2015-07-13 12:39:09 -07:00
be757066f5 [Mobile] Desktop adjusted
Adjusted the desktop to accomodate browser
orientation changes. Done so by forgoing
checking the orientation because the
actual device can be in landscape, but it
reads orientation based on the viewport.
2015-07-13 11:18:51 -07:00
885433390e [Mobile] Fix for emu and act
Adds 2 landscape conditions for tablets and
phones to check if they are in landscape, in
the actual tablet, or in an emulate of the tablet,
then it displays.
2015-07-13 10:32:58 -07:00
687f810475 [Mobile] Constants
Fixed width constant to work for laptop.
2015-07-13 10:23:28 -07:00
137a60f510 [Mobile] Constants
Fixed constants to work for laptop.
2015-07-13 10:16:52 -07:00
46d5a1431f [Mobile] Added Constants
Rixed mis-initialized desktop
constant
2015-07-13 09:24:01 -07:00
404d02ec23 [Mobile] Added Constants
Re-edited constants to set min
ones for the desktop screen, that
is based on the device size.
2015-07-13 09:17:59 -07:00
eec955317a revert back to
4d9dc3624b
2015-07-10 12:47:00 -07:00
67890a7298 [Mobile] Test 2015-07-10 12:38:04 -07:00
dd457f26c6 [Mobile] Device
Added max width to tablet check.
2015-07-10 12:32:34 -07:00
85c6bda5c9 [Mobile] Device
Adjusted Tablet slide Constant.
2015-07-10 12:21:13 -07:00
b7b5f87002 [Mobile] Device
Adjusted Comp Constant.
2015-07-10 12:16:43 -07:00
b0c5d807e7 [Mobile] Device
Removes splits desktop
settings into 2, one
for landscape and another
for portrait.
2015-07-10 11:51:56 -07:00
4d4776e0ef [Mobile] Device
Removes desktop mixin settings
that do not use device width and
height.
2015-07-10 11:40:57 -07:00
61e1aeb1d8 [Mobile] Device
Removes desktop mixin settings
that do not use device width and
height.
2015-07-10 11:40:14 -07:00
9caa603a65 [Mobile] Device
Removes desktop mixin settings
that do not use device width and
height.
2015-07-10 11:36:45 -07:00
5c99e469d5 [Mobile] Device Change
Now instead of min-width, max-width,
... etc, uses the device-width/height.
This allows the devices to use the slide
menu while the browser on a desktop
consistently stays as desktop mode, no
matter if it is resized. As a result of this
the rwd is clear on phones/tablets, but not if
user resizes browser super small.
2015-07-10 11:29:30 -07:00
4d9dc3624b [Mobile] Items
Item icons disappear now on
tablets and mobile devices.
Adjusted _items.scss to adjust the
icon class display for phones and
tablets.
2015-07-10 11:12:09 -07:00
d3ae4b729f [Mobile] More consistent
More consistent when moving from
landscape to portrait and
vice-versa on devices. However
still encountering issue with
the browser being resized.
2015-07-10 10:56:48 -07:00
30bed434fe [Mobile] Moved variables
Moved variables used for amount of
side bar and slide amount into the
mobile/_constants.scss file.
2015-07-10 09:02:46 -07:00
3e4ae4d38d [Mobile]
Reverted changes to original controller file.
2015-07-09 15:38:53 -07:00
7414275a85 [Mobile]
Reverted changes to original scss file.
2015-07-09 15:37:03 -07:00
fcb0033864 [Mobile]
Reverted changes to css file.
2015-07-09 15:32:41 -07:00
f079471a18 [Mobile]
Reverted changes to scss file.
2015-07-09 15:31:35 -07:00
1fb1174c0a [Mobile] Clean-Up
Removed unused scss constant
.
2015-07-09 15:19:29 -07:00
635e1eda69 [Mobile] Clean-Up
Removed unused menu button and
cleaned up treeCl to be treeClass.
2015-07-09 15:14:36 -07:00
40d53f941f [Mobile] TreeMenuController
Removed the TreeMenuController.js file
and from the bundle. What this achieves
is already done in BrowseController.js
2015-07-09 14:46:36 -07:00
684a0e88a2 [Mobile] Constants
Added constants to the
mobile one with device
height.
2015-07-09 14:26:02 -07:00
30a4f15330 [Mobile] Adjusted
Adjusted the _layout.scss to
have a function that makes
something disappear on phone
and tablet.
2015-07-09 14:11:51 -07:00
dfd08000f1 [Mobile] Adjust
Adjusted the tablet amount
that the slide occurs.
2015-07-09 13:42:07 -07:00
82c8d26264 [Mobile]
Now does not display
the icon for the slide menu
on desktops.
2015-07-09 11:16:41 -07:00
bd236e1cb1 [Mobile] Icon
Added menu/hamburger icon.
2015-07-09 11:06:25 -07:00
e47a36e799 [Mobile] Simplified
treeSlide now uses one line that
sets it to true or false simply
like a switch. So not matter what
it will either slide or not.
2015-07-09 10:55:52 -07:00
30efec0090 [Mobile] Angular
Replaced document usage with
angular calls that change the ternary
op to flip the slide.
2015-07-09 10:53:03 -07:00
b9371ea03d [Mobile] Moved Button
Button moved to the Browse.html
and BrowseController handles the
tree slide.
2015-07-09 10:28:45 -07:00
7974f33781 [Mobile] Phone
Adjusted to differentiate
phones and tablets.
2015-07-08 16:28:40 -07:00
cdcaedc8dd [Mobile] Added transistions
Transistions added, however still using
document.getElementById.
2015-07-08 15:57:08 -07:00
07ef4dfe8a [Mobile] Menu Slide
Menu slides, but not transition
css slides out on click. Currently
uses document, which needs to be
replaced with angular version using
 and/or  and/or
ng-class and/or ng-click.
2015-07-08 14:27:59 -07:00
342be0822f [Mobile] Gen css 2015-07-08 12:17:19 -07:00
5c56484889 [Mobile] Main scss added
Added the mobile files as imports
to the main scss files that
generate as css files.
2015-07-08 12:14:40 -07:00
2b4162c0be [Mobile] Reorganize
Reorganized the sass files. To incorporate, new
mobile directory, which holds all the mobile
sass code.
2015-07-08 12:11:48 -07:00
3704d64560 [Mobile] Push to show current 2015-07-08 11:08:31 -07:00
24fae72492 [Mobile] Left tree
Attempt to resize left
tree menu when changing device.
Currently does not move the splitter
bar.
2015-07-07 16:46:32 -07:00
79fb6eabd9 [Mobile] Menu Button
Menu button added to the
bundle and as a file modelled
after the action button.
2015-07-07 16:28:34 -07:00
1ddb00c8d6 [Mobile] Resize
Resized the height of each
item in grid based on new
tablet/phone widths.
2015-07-07 14:01:57 -07:00
8a0b77ec5c [Mobile] Folder View
Folder representation now
will be a list.
2015-07-07 13:02:40 -07:00
2fc447e16f [Mobile] Comments
Added comments and reverted the
grid back to normal.
2015-07-07 10:15:25 -07:00
d828bf59f9 [Mobile] Constants/Etc
Added constants for media queries.
in _constants.scss. Also, now on tablet,
zoom is disabled.
2015-07-07 09:58:22 -07:00
d8806f14aa [Mobile] Set viewport
Viewport has been set in
index.html. Then what was
implemented prior to this
(rem-display and browser-manage)
was commented out.
2015-07-07 09:08:16 -07:00
0c6a9ca857 [Mobile] Styles
Added new style to set the width
of the tree.
2015-07-06 13:15:38 -07:00
07c907b315 Merge remote-tracking branch 'upstream/master' 2015-07-02 13:14:27 -07:00
d343d38037 Merge remote-tracking branch 'upstream/master' 2015-07-01 13:30:08 -07:00
73241efdc8 [Fix] Fixes bundle
Changes the persistance to the example
version.
2015-06-30 13:20:46 -07:00
b40494ac95 plot-reborn WIP 2015-06-12 13:53:53 -07:00
78 changed files with 4550 additions and 242 deletions

View File

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

View File

@ -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"

View File

@ -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": [

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

View File

@ -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' }">

View File

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

View File

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

View File

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

View File

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

View File

@ -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
@ -127,6 +126,36 @@ define(
}
}
// 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)
// navigate to one of them, so that navigation state has
@ -141,6 +170,12 @@ define(
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);
@ -152,6 +187,10 @@ define(
navigationService.removeListener(setNavigation);
});
$scope.backArrow = navigateToParent;
$scope.checkRoot = checkRoot;
}
return BrowseController;

View File

@ -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(
@ -89,6 +92,17 @@ define(
[ "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
}));
@ -146,6 +160,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(
"$destroy",
@ -238,6 +259,103 @@ define(
);
});
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

@ -59,7 +59,7 @@
"glyph": "Z",
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [ "$q" ]
"depends": [ "$q", "navigationService" ]
},
{
"key": "save",

View File

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

View File

@ -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 () {

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@ -26,5 +26,8 @@
@import "compass/utilities";
@import "constants";
@import "mobile/constants";
@import "mixins";
@import "mobile/mixins";
@import "items/item";
@import "mobile/item";

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

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

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

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

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

View File

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

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

@ -20,5 +20,6 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
@import "constants";
@import "mobile/constants";
@import "themes/theme-espresso";
@import "main";

View File

@ -26,5 +26,8 @@
@import "compass/utilities";
@import "constants";
@import "mobile/constants";
@import "mixins";
@import "mobile/mixins";
@import "tree/tree";
@import "mobile/tree";

View File

@ -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) {

View File

@ -265,6 +265,7 @@
&.vertical {
// Slides left and right
>.pane {
// @include test();
margin-left: $interiorMargin;
>.holder {
left: 0;

View File

@ -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"

View File

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

View File

@ -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'"
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"

View File

@ -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;
@ -87,6 +87,10 @@ define(
}
}
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

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

View File

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

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

View File

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

View File

@ -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,7 +47,8 @@
"$compile",
"$document",
"$window",
"$rootScope"
"$rootScope",
"agentService"
]
}
],
@ -46,6 +57,13 @@
"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, infoService, DELAY, element, domainObject) {
function InfoGesture($timeout, agentService, infoService, DELAY, element, domainObject) {
var dismissBubble,
pendingBubble,
mousePosition,
@ -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

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,19 +54,30 @@ 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);

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

View File

@ -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,

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

@ -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.

View 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."
}
]
}
}

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

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

View File

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

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

View File

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

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

View File

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

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

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

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

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

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

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

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

View File

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

View File

@ -17,7 +17,7 @@
},
{
"key": "ELASTIC_ROOT",
"value": "http://localhost:9200",
"value": "/elastic",
"priority": "fallback"
},
{

View File

@ -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" ]
}
]
}

View File

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

View File

@ -39,15 +39,39 @@ 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 {
/**

View File

@ -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;
@ -77,6 +89,7 @@ define(
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);
}
});
});
});
}
);

View File

@ -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"]);
mockContextMenuAction = jasmine.createSpyObj(
"action",
[ "perform", "getActions" ]
);
mockActionContext = jasmine.createSpyObj(
"actionContext",
[ "" ]
);
gesture = new ContextMenuGesture(mockElement, mockDomainObject);
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);
});
});
}
);