Merge branch 'master' into nem468a.
Many tweaks to fix some issues with tree, labels and Inspector. Conflicts: platform/commonUI/edit/res/templates/elements.html platform/commonUI/general/res/sass/search/_search.scss platform/commonUI/general/res/sass/tree/_tree.scss platform/commonUI/general/res/templates/object-inspector.html platform/commonUI/themes/espresso/res/css/theme-espresso.css platform/commonUI/themes/snow/res/css/theme-snow.css platform/search/res/templates/search.html
This commit is contained in:
@@ -116,10 +116,6 @@
|
||||
"implementation": "controllers/GetterSetterController.js",
|
||||
"depends": [ "$scope" ]
|
||||
},
|
||||
{
|
||||
"key": "SplitPaneController",
|
||||
"implementation": "controllers/SplitPaneController.js"
|
||||
},
|
||||
{
|
||||
"key": "SelectorController",
|
||||
"implementation": "controllers/SelectorController.js",
|
||||
|
||||
@@ -35,24 +35,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.l-autoflow-header {
|
||||
bottom: auto;
|
||||
height: $headerH;
|
||||
line-height: $headerH;
|
||||
min-width: $colW;
|
||||
span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
min-width: $colW;
|
||||
.t-last-update {
|
||||
overflow: hidden;
|
||||
}
|
||||
.s-btn.change-column-width {
|
||||
@include trans-prop-nice-fade(500ms);
|
||||
opacity: 0;
|
||||
}
|
||||
.l-filter {
|
||||
margin-left: $interiorMargin;
|
||||
display: block;
|
||||
margin-right: $interiorMargin;
|
||||
input.t-filter-input {
|
||||
width: 100px;
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,4 +126,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.frame {
|
||||
&.child-frame.panel {
|
||||
.autoflow .l-autoflow-header .l-filter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ $itemPadLR: 5px;
|
||||
$treeVCW: 10px;
|
||||
$treeTypeIconH: 1.4em; // was 16px
|
||||
$treeTypeIconHPx: 16px;
|
||||
$treeTypeIconW: 20px;
|
||||
$treeTypeIconW: 18px;
|
||||
$treeContextTriggerW: 20px;
|
||||
// Tabular
|
||||
$tabularHeaderH: 22px; //18px
|
||||
|
||||
@@ -31,10 +31,6 @@ a.disabled {
|
||||
border-bottom: 1px solid rgba(#fff, 0.3);
|
||||
}
|
||||
|
||||
.outline {
|
||||
@include boxOutline();
|
||||
}
|
||||
|
||||
.test-stripes {
|
||||
@include bgDiagonalStripes();
|
||||
}
|
||||
|
||||
@@ -73,31 +73,34 @@
|
||||
}
|
||||
|
||||
.l-icon-alert {
|
||||
display: none !important; // Remove this when alerts are enabled
|
||||
display: none !important;
|
||||
&:before {
|
||||
color: $colorAlert;
|
||||
content: "!";
|
||||
}
|
||||
}
|
||||
|
||||
// NEW!!
|
||||
.t-item-icon {
|
||||
// Used in grid-item.html, tree-item, inspector location, more?
|
||||
@extend .ui-symbol;
|
||||
@extend .icon;
|
||||
display: inline-block;
|
||||
line-height: normal; // This is Ok for the symbolsfont
|
||||
position: relative;
|
||||
.t-item-icon-glyph {
|
||||
position: absolute;
|
||||
}
|
||||
&.l-icon-link {
|
||||
&:before {
|
||||
color: $colorIconLink;
|
||||
content: "\f4";
|
||||
height: auto; width: auto;
|
||||
position: absolute;
|
||||
left: 0; top: 0; right: 0; bottom: 10%;
|
||||
@include transform-origin(bottom, left);
|
||||
@include transform(scale(0.3));
|
||||
z-index: 2;
|
||||
.t-item-icon-glyph {
|
||||
&:before {
|
||||
color: $colorIconLink;
|
||||
content: "\f4";
|
||||
height: auto; width: auto;
|
||||
position: absolute;
|
||||
left: 0; top: 0; right: 0; bottom: 10%;
|
||||
@include transform-origin(bottom, left);
|
||||
@include transform(scale(0.3));
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,10 +98,19 @@
|
||||
|
||||
.inspector-location {
|
||||
.location-item {
|
||||
$h: 1.2em;
|
||||
@include box-sizing(border-box);
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
line-height: $h;
|
||||
position: relative;
|
||||
padding: 2px 4px;
|
||||
.t-object-label {
|
||||
.t-item-icon {
|
||||
height: $h;
|
||||
width: 0.7rem;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
color: $colorItemTreeHoverFg;
|
||||
@@ -116,6 +125,7 @@
|
||||
display: inline-block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 8px;
|
||||
font-style: normal !important;
|
||||
line-height: inherit;
|
||||
margin-left: $interiorMarginSm;
|
||||
width: 4px;
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
@import "overlay/overlay";
|
||||
@import "mobile/overlay/overlay";
|
||||
@import "tree/tree";
|
||||
@import "object-label";
|
||||
@import "mobile/tree";
|
||||
@import "user-environ/frame";
|
||||
@import "user-environ/top-bar";
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
@include desktop {
|
||||
@if $bgHov != none {
|
||||
&:not(.disabled):hover {
|
||||
background: $bgHov;
|
||||
@include background-image($bgHov);
|
||||
>.icon {
|
||||
color: lighten($ic, $ltGamma);
|
||||
}
|
||||
|
||||
69
platform/commonUI/general/res/sass/_object-label.scss
Normal file
69
platform/commonUI/general/res/sass/_object-label.scss
Normal file
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
// mct-representation surrounding an object-label key="'label'"
|
||||
.rep-object-label {
|
||||
@include flex-direction(row);
|
||||
@include flex(1 1 auto);
|
||||
height: inherit;
|
||||
line-height: inherit;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.t-object-label {
|
||||
.t-item-icon {
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
mct-representation {
|
||||
&.s-status-pending {
|
||||
.t-object-label {
|
||||
.t-item-icon {
|
||||
&:before {
|
||||
$spinBW: 4px;
|
||||
$spinD: 0;
|
||||
@include spinner($spinBW);
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
padding: 30%;
|
||||
width: $spinD;
|
||||
height: $spinD;
|
||||
}
|
||||
.t-item-icon-glyph {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.t-title-label {
|
||||
font-style: italic;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.selected mct-representation.s-status-pending .t-object-label .t-item-icon:before {
|
||||
border-color: rgba($colorItemTreeSelectedFg, 0.25);
|
||||
border-top-color: rgba($colorItemTreeSelectedFg, 1.0);
|
||||
}
|
||||
@@ -37,6 +37,8 @@
|
||||
}
|
||||
|
||||
.status.block {
|
||||
$transDelay: 1.5s;
|
||||
$transSpeed: .25s;
|
||||
color: $colorStatusDefault;
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
@@ -44,13 +46,47 @@
|
||||
.status-indicator,
|
||||
.label,
|
||||
.count {
|
||||
//@include test(#00ff00);
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&.no-icon {
|
||||
.status-indicator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.float-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
&.subtle {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.status-indicator {
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&:not(.no-collapse) {
|
||||
.label {
|
||||
// Max-width silliness is necessary for width transition
|
||||
@include trans-prop-nice(max-width, $transSpeed, $transDelay);
|
||||
overflow: hidden;
|
||||
max-width: 0px;
|
||||
}
|
||||
&:hover {
|
||||
.label {
|
||||
@include trans-prop-nice(max-width, $transSpeed, 0s);
|
||||
max-width: 450px;
|
||||
width: auto;
|
||||
}
|
||||
.count {
|
||||
@include trans-prop-nice(max-width, $transSpeed, 0s);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.ok .status-indicator,
|
||||
&.info .status-indicator {
|
||||
color: $colorStatusInfo;
|
||||
@@ -63,26 +99,11 @@
|
||||
&.error .status-indicator {
|
||||
color: $colorStatusError;
|
||||
}
|
||||
.label {
|
||||
// Max-width silliness is necessary for width transition
|
||||
@include trans-prop-nice(max-width, .25s);
|
||||
overflow: hidden;
|
||||
max-width: 0px;
|
||||
}
|
||||
.count {
|
||||
@include trans-prop-nice(opacity, .25s);
|
||||
@include trans-prop-nice(opacity, $transSpeed, $transDelay);
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
&:hover {
|
||||
.label {
|
||||
max-width: 450px;
|
||||
width: auto;
|
||||
}
|
||||
.count {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles for messages and message banners */
|
||||
|
||||
@@ -24,21 +24,27 @@
|
||||
100% { transform: rotate(359deg); }
|
||||
}
|
||||
|
||||
@mixin wait-spinner2($b: 5px, $c: $colorAlt1) {
|
||||
@mixin spinner($b: 5px) {
|
||||
@include keyframes(rotateCentered) {
|
||||
0% { transform: translateX(-50%) translateY(-50%) rotate(0deg); }
|
||||
100% { transform: translateX(-50%) translateY(-50%) rotate(359deg); }
|
||||
}
|
||||
0% { @include transform(translateX(-50%) translateY(-50%) rotate(0deg)); }
|
||||
100% { @include transform(translateX(-50%) translateY(-50%) rotate(359deg)); }
|
||||
}
|
||||
@include animation-name(rotateCentered);
|
||||
@include animation-duration(0.5s);
|
||||
@include animation-iteration-count(infinite);
|
||||
@include animation-timing-function(linear);
|
||||
@include transform-origin(center);
|
||||
border-style: solid;
|
||||
border-width: $b;
|
||||
@include border-radius(100%);
|
||||
}
|
||||
|
||||
|
||||
@mixin wait-spinner2($b: 5px, $c: $colorAlt1) {
|
||||
@include spinner($b);
|
||||
@include box-sizing(border-box);
|
||||
border-color: rgba($c, 0.25);
|
||||
border-top-color: rgba($c, 1.0);
|
||||
border-style: solid;
|
||||
border-width: 5px;
|
||||
@include border-radius(100%);
|
||||
@include box-sizing(border-box);
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 0; width: 0;
|
||||
|
||||
@@ -31,7 +31,7 @@ $tabletItemH: floor($ueBrowseGridItemLg/3);
|
||||
|
||||
/************************** MOBILE TREE MENU DIMENSIONS */
|
||||
$mobileTreeItemH: 35px;
|
||||
$mobileTreeItemIndent: 20px;
|
||||
$mobileTreeItemIndent: 15px;
|
||||
$mobileTreeRightArrowW: 30px;
|
||||
|
||||
/************************** DEVICE WIDTHS */
|
||||
|
||||
@@ -30,25 +30,30 @@
|
||||
}
|
||||
.tree-item,
|
||||
.search-result-item {
|
||||
height: $mobileTreeItemH;
|
||||
line-height: $mobileTreeItemH;
|
||||
margin-bottom: 0px;
|
||||
height: $mobileTreeItemH !important;
|
||||
line-height: $mobileTreeItemH !important;
|
||||
margin-bottom: 0px !important;
|
||||
.view-control {
|
||||
//@include test(red);
|
||||
position: absolute;
|
||||
font-size: 1.1em;
|
||||
height: $mobileTreeItemH;
|
||||
line-height: inherit;
|
||||
right: 0px;
|
||||
width: $mobileTreeRightArrowW;
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
margin-right: 0;
|
||||
order: 2;
|
||||
width: $mobileTreeItemH;
|
||||
&.has-children {
|
||||
&:before {
|
||||
content: "\7d";
|
||||
left: 50%;
|
||||
@include transform(translateX(-50%) rotate(90deg));
|
||||
}
|
||||
&.expanded:before {
|
||||
@include transform(translateX(-50%) rotate(270deg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label,
|
||||
.t-object-label {
|
||||
left: 0;
|
||||
right: $mobileTreeRightArrowW + $interiorMargin; // Allows tree item name to stop prior to the arrow
|
||||
line-height: inherit;
|
||||
.t-item-icon.l-icon-link .t-item-icon-glyph:before {
|
||||
bottom: 20%; // Shift up due to height of mobile menu items
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@include phone {
|
||||
.search {
|
||||
.search-holder {
|
||||
.search-bar {
|
||||
// Hide menu-icon and adjust spacing when in phone mode
|
||||
.menu-icon {
|
||||
|
||||
@@ -20,33 +20,92 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
.holder-search {
|
||||
// Moved a lot of stuff in here to _filter.scss
|
||||
// to generalize approach to search input controls.
|
||||
.clear-icon,
|
||||
.menu-icon {
|
||||
cursor: pointer;
|
||||
font-family: symbolsfont;
|
||||
@include trans-prop-nice((opacity, color), 150ms);
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
// 'x' in circle icon
|
||||
&:before {
|
||||
content: '\e607';
|
||||
}
|
||||
}
|
||||
|
||||
.holder-search {
|
||||
$iconWidth: 20px;
|
||||
$textInputHeight: 19px;
|
||||
$iconEdgeM: 4px;
|
||||
$iconD: $treeSearchInputBarH - ($iconEdgeM*2);
|
||||
|
||||
.search-bar {
|
||||
$textInputHeight: 19px; // This is equal to the default value, 19px
|
||||
$iconEdgeM: 4px;
|
||||
$iconD: $treeSearchInputBarH - ($iconEdgeM*2);
|
||||
font-size: 0.8em;
|
||||
max-width: 250px;
|
||||
position: relative;
|
||||
|
||||
input[type="search"] {
|
||||
.search-input {
|
||||
height: $treeSearchInputBarH;
|
||||
line-height: $treeSearchInputBarH;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-left: $iconD + $interiorMargin !important;
|
||||
padding-right: ($iconD * 2) + ($interiorMargin * 2) !important;
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
right: $iconD + $interiorMargin;
|
||||
&:before,
|
||||
.clear-icon,
|
||||
.menu-icon {
|
||||
@include box-sizing(border-box);
|
||||
color: $colorInputIcon;
|
||||
height: $iconD;
|
||||
width: $iconD;
|
||||
line-height: $iconD;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: $iconEdgeM;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-left: $iconD + $interiorMargin !important;
|
||||
padding-right: ($iconD * 2) + ($interiorMargin * 2) !important;
|
||||
|
||||
// Make work for mct-control textfield
|
||||
input {
|
||||
width: inherit; // was 100%
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
// Magnify glass icon
|
||||
content:'\4d';
|
||||
font-family: symbolsfont;
|
||||
left: $interiorMarginSm;
|
||||
@include trans-prop-nice(color, 250ms);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
// Make icon lighten when hovering over search bar
|
||||
&:hover:before {
|
||||
color: pullForward($colorInputIcon, 10%);
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
right: $iconD + $interiorMargin;
|
||||
|
||||
// Icon is visible only when there is text input
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
&.show {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: pullForward($colorInputIcon, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
// 'v' invoke menu icon
|
||||
&:before { content: '\76'; }
|
||||
@@ -69,7 +128,7 @@
|
||||
}
|
||||
|
||||
.active-filter-display {
|
||||
$s: 0.65em;
|
||||
$s: 0.7em;
|
||||
$p: $interiorMargin;
|
||||
@include box-sizing(border-box);
|
||||
line-height: 130%;
|
||||
@@ -88,7 +147,6 @@
|
||||
|
||||
.search-results {
|
||||
@include trans-prop-nice((opacity, visibility), 250ms);
|
||||
margin-top: $interiorMarginLg; // Always include margin here to fend off the search input
|
||||
padding-right: $interiorMargin;
|
||||
.hint {
|
||||
margin-bottom: $interiorMarginLg;
|
||||
|
||||
@@ -35,23 +35,35 @@ ul.tree {
|
||||
.tree-item,
|
||||
.search-result-item {
|
||||
$runningItemW: 0;
|
||||
@extend .l-flex-row;
|
||||
@include box-sizing(border-box);
|
||||
@include border-radius($basicCr);
|
||||
@include single-transition(background-color, 0.25s);
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
height: $menuLineH;
|
||||
line-height: $menuLineH;
|
||||
margin-bottom: $interiorMarginSm;
|
||||
padding: 0 $interiorMarginSm;
|
||||
position: relative;
|
||||
|
||||
.view-control {
|
||||
color: $colorItemTreeVC;
|
||||
display: inline-block;
|
||||
margin-left: $interiorMargin;
|
||||
font-size: 0.75em;
|
||||
font-size: 0.75em;
|
||||
margin-right: $interiorMargin;
|
||||
height: 100%;
|
||||
line-height: inherit;
|
||||
width: $treeVCW;
|
||||
$runningItemW: $interiorMargin + $treeVCW;
|
||||
&.has-children {
|
||||
&:before {
|
||||
position: absolute;
|
||||
@include trans-prop-nice(transform, 100ms);
|
||||
content: "\3e";
|
||||
@include transform-origin(center);
|
||||
}
|
||||
&.expanded:before {
|
||||
@include transform(rotate(90deg));
|
||||
}
|
||||
}
|
||||
@include desktop {
|
||||
&:hover {
|
||||
color: $colorItemTreeVCHover !important;
|
||||
@@ -59,64 +71,17 @@ ul.tree {
|
||||
}
|
||||
}
|
||||
|
||||
.label,
|
||||
.t-object-label {
|
||||
display: block;
|
||||
@include absPosDefault();
|
||||
line-height: $menuLineH;
|
||||
|
||||
.t-item-icon {
|
||||
@include txtShdwSubtle($shdwItemTreeIcon);
|
||||
font-size: $treeTypeIconH;
|
||||
color: $colorItemTreeIcon;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: 50%;
|
||||
width: $treeTypeIconH;
|
||||
@include transform(translateY(-50%));
|
||||
width: $treeTypeIconW;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
//@include absPosDefault(0, false);
|
||||
$d: $treeTypeIconH;
|
||||
@include txtShdwSubtle($shdwItemTreeIcon);
|
||||
font-size: $treeTypeIconH;
|
||||
color: $colorItemTreeIcon;
|
||||
left: $interiorMargin;
|
||||
position: absolute;
|
||||
@include verticalCenterBlock($menuLineHPx, $treeTypeIconHPx);
|
||||
line-height: 100%;
|
||||
right: auto; width: $treeTypeIconH;
|
||||
|
||||
.icon {
|
||||
&.l-icon-link,
|
||||
&.l-icon-alert {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
&.l-icon-alert {
|
||||
$d: 8px;
|
||||
@include ancillaryIcon($d, $colorAlert);
|
||||
top: 1px;
|
||||
right: -2px;
|
||||
}
|
||||
&.l-icon-link {
|
||||
$d: 8px;
|
||||
@include ancillaryIcon($d, $colorIconLink);
|
||||
left: -3px;
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.title-label,
|
||||
.t-title-label {
|
||||
@include absPosDefault();
|
||||
display: block;
|
||||
left: $runningItemW + ($interiorMargin * 3);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@include ellipsize();
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
@@ -126,12 +91,11 @@ ul.tree {
|
||||
color: $colorItemTreeSelectedVC;
|
||||
}
|
||||
.t-object-label .t-item-icon {
|
||||
color: $colorItemTreeSelectedFg; //$colorItemTreeIconHover;
|
||||
color: $colorItemTreeSelectedFg;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.selected) {
|
||||
// NOTE: [Mobile] Removed Hover on Mobile
|
||||
@include desktop {
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
@@ -160,6 +124,31 @@ ul.tree {
|
||||
}
|
||||
}
|
||||
|
||||
mct-representation {
|
||||
&.s-status-pending {
|
||||
.t-object-label {
|
||||
.t-item-icon {
|
||||
&:before {
|
||||
$spinBW: 4px;
|
||||
@include spinner($spinBW);
|
||||
border-color: rgba($colorItemTreeIcon, 0.25);
|
||||
border-top-color: rgba($colorItemTreeIcon, 1.0);
|
||||
}
|
||||
.t-item-icon-glyph {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.t-title-label {
|
||||
font-style: italic;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.selected mct-representation.s-status-pending .t-object-label .t-item-icon:before {
|
||||
border-color: rgba($colorItemTreeSelectedFg, 0.25);
|
||||
border-top-color: rgba($colorItemTreeSelectedFg, 1.0);
|
||||
}
|
||||
.tree .tree-item,
|
||||
.search-results .s-status-editing .search-result-item {
|
||||
.t-object-label {
|
||||
|
||||
@@ -302,6 +302,7 @@
|
||||
.splitter-treeview,
|
||||
.holder-treeview-elements {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +334,7 @@
|
||||
.l-inspect,
|
||||
.splitter-inspect {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<span ng-controller="SplitPaneController as splitter">
|
||||
<div class="splitter" ng-style="splitter.style()"
|
||||
mct-drag="splitter.move(delta.x)">
|
||||
</div>
|
||||
<div class='split-pane-component items pane' style="right:0;"
|
||||
ng-style="splitter.style()"
|
||||
ng-transclude>
|
||||
</div>
|
||||
</span>
|
||||
@@ -20,7 +20,6 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<!--<div ng-init="reps = [1,2,3]"></div>-->
|
||||
<div class='status block'
|
||||
title="{{ngModel.getDescription()}}"
|
||||
ng-click='ngModel.configure()'
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span class="t-object-label">
|
||||
<span class="t-item-icon" ng-class="{ 'l-icon-link':location.isLink() }">{{type.getGlyph()}}</span>
|
||||
<span class='t-title-label'>{{model.name}}</span>
|
||||
</span>
|
||||
<div class="t-object-label l-flex-row flex-elem grows">
|
||||
<div class="t-item-icon flex-elem" ng-class="{ 'l-icon-link':location.isLink() }">
|
||||
<div class="t-item-icon-glyph">{{type.getGlyph()}}</div>
|
||||
</div>
|
||||
<div class='t-title-label flex-elem grows'>{{model.name}}</div>
|
||||
</div>
|
||||
|
||||
@@ -20,61 +20,44 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span class="l-inspect" ng-controller="ObjectInspectorController as controller">
|
||||
<div ng-controller="PaneController as modelPaneEdit">
|
||||
<mct-split-pane class='abs contents split-layout' anchor='bottom'>
|
||||
<div class="split-pane-component pane top">
|
||||
<div class="abs holder holder-inspector l-flex-col">
|
||||
<div class="pane-header flex-elem">Inspection</div>
|
||||
<ul class="flex-elem grows vscroll">
|
||||
<li>
|
||||
<em>Properties</em>
|
||||
<div class="inspector-properties"
|
||||
ng-repeat="data in metadata"
|
||||
ng-class="{ first:$index === 0 }">
|
||||
<div class="label">{{ data.name }}</div>
|
||||
<div class="value">{{ data.value }}</div>
|
||||
</div>
|
||||
</li>
|
||||
<li ng-if="contextutalParents.length > 0">
|
||||
<em title="The location of this linked object.">Location</em>
|
||||
<span class="inspector-location"
|
||||
ng-repeat="parent in contextutalParents"
|
||||
ng-class="{ last:($index + 1) === contextualParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
</li>
|
||||
<li ng-if="primaryParents.length > 0">
|
||||
<em title="The location of the original object that this was linked from.">Original Location</em>
|
||||
<span class="inspector-location"
|
||||
ng-repeat="parent in primaryParents"
|
||||
ng-class="{ last:($index + 1) === primaryParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!--/ holder-inspector -->
|
||||
</div><!--/ split-pane-component -->
|
||||
<mct-splitter class="splitter-inspect-panel mobile-hide"></mct-splitter>
|
||||
<div class="split-pane-component pane bottom">
|
||||
<div class="abs holder holder-elements l-flex-col">
|
||||
<em class="flex-elem">Elements</em>
|
||||
<mct-representation
|
||||
key="'edit-elements'"
|
||||
mct-object="domainObject"
|
||||
class="flex-elem holder grows vscroll current-elements">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<div class="abs holder holder-inspector-elements l-flex-col">
|
||||
<div class="pane-header flex-elem">Inspection</div>
|
||||
<ul class="flex-elem grows vscroll">
|
||||
<li>
|
||||
<em>Properties</em>
|
||||
<div class="inspector-properties"
|
||||
ng-repeat="data in metadata"
|
||||
ng-class="{ first:$index === 0 }">
|
||||
<div class="label">{{ data.name }}</div>
|
||||
<div class="value">{{ data.value }}</div>
|
||||
</div>
|
||||
</mct-split-pane>
|
||||
</div><!--/ PaneController -->
|
||||
</li>
|
||||
<li ng-if="contextutalParents.length > 0">
|
||||
<em title="The location of this linked object.">Location</em>
|
||||
<span class="inspector-location"
|
||||
ng-repeat="parent in contextutalParents"
|
||||
ng-class="{ last:($index + 1) === contextualParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item rep-object-label">
|
||||
</mct-representation>
|
||||
</span>
|
||||
</li>
|
||||
<li ng-if="primaryParents.length > 0">
|
||||
<em title="The location of the original object that this was linked from.">Original Location</em>
|
||||
<span class="inspector-location"
|
||||
ng-repeat="parent in primaryParents"
|
||||
ng-class="{ last:($index + 1) === primaryParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item rep-object-label">
|
||||
</mct-representation>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
@@ -26,42 +26,19 @@
|
||||
ng-class="{selected: treeNode.isSelected()}"
|
||||
>
|
||||
<span
|
||||
mct-device="desktop"
|
||||
class='ui-symbol view-control'
|
||||
class='ui-symbol view-control flex-elem'
|
||||
ng-class="{ 'has-children': model.composition !== undefined, expanded: toggle.isActive() }"
|
||||
ng-click="toggle.toggle(); treeNode.trackExpansion()"
|
||||
ng-if="model.composition !== undefined"
|
||||
>
|
||||
{{toggle.isActive() ? "v" : ">"}}
|
||||
</span>
|
||||
|
||||
<mct-representation
|
||||
mct-device="desktop"
|
||||
class="mobile-hide"
|
||||
class="rep-object-label"
|
||||
key="'label'"
|
||||
mct-object="domainObject"
|
||||
parameters="{suppressMenuOnEdit: true}"
|
||||
ng-click="treeNode.select()"
|
||||
>
|
||||
</mct-representation>
|
||||
<mct-representation
|
||||
mct-device="mobile"
|
||||
class="desktop-hide"
|
||||
key="'label'"
|
||||
mct-object="domainObject"
|
||||
ng-click="(model.composition === undefined) && treeNode.select();
|
||||
toggle.toggle();
|
||||
treeNode.trackExpansion();"
|
||||
>
|
||||
</mct-representation>
|
||||
|
||||
<span
|
||||
mct-device="mobile"
|
||||
class='ui-symbol view-control'
|
||||
ng-model="ngModel"
|
||||
ng-click="treeNode.select()"
|
||||
>
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="tree-item-subtree"
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* 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 DEFAULT_MAXIMUM = 1000,
|
||||
DEFAULT_MINIMUM = 120;
|
||||
|
||||
/**
|
||||
* Controller for the splitter in Browse mode. Current implementation
|
||||
* uses many hard-coded constants; this could be generalized.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function SplitPaneController() {
|
||||
this.current = 200;
|
||||
this.start = 200;
|
||||
this.assigned = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current position of the splitter, in pixels
|
||||
* from the left edge.
|
||||
* @returns {number} position of the splitter, in pixels
|
||||
*/
|
||||
SplitPaneController.prototype.state = function (defaultState) {
|
||||
// Set the state to the desired default, if we don't have a
|
||||
// "real" current state yet.
|
||||
if (arguments.length > 0 && !this.assigned) {
|
||||
this.current = defaultState;
|
||||
this.assigned = true;
|
||||
}
|
||||
return this.current;
|
||||
};
|
||||
|
||||
/**
|
||||
* Begin moving the splitter; this will note the splitter's
|
||||
* current position, which is necessary for correct
|
||||
* interpretation of deltas provided by mct-drag.
|
||||
*/
|
||||
SplitPaneController.prototype.startMove = function () {
|
||||
this.start = this.current;
|
||||
};
|
||||
|
||||
/**
|
||||
* Move the splitter a number of pixels to the right
|
||||
* (negative numbers move the splitter to the left.)
|
||||
* This movement is relative to the position of the
|
||||
* splitter when startMove was last invoked.
|
||||
* @param {number} delta number of pixels to move
|
||||
*/
|
||||
SplitPaneController.prototype.move = function (delta, minimum, maximum) {
|
||||
// Ensure defaults for minimum/maximum
|
||||
maximum = isNaN(maximum) ? DEFAULT_MAXIMUM : maximum;
|
||||
minimum = isNaN(minimum) ? DEFAULT_MINIMUM : minimum;
|
||||
|
||||
// Update current splitter state
|
||||
this.current = Math.min(
|
||||
maximum,
|
||||
Math.max(minimum, this.start + delta)
|
||||
);
|
||||
};
|
||||
|
||||
return SplitPaneController;
|
||||
}
|
||||
);
|
||||
@@ -22,8 +22,8 @@
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/controllers/DateTimePickerController"],
|
||||
function (DateTimePickerController) {
|
||||
["../../src/controllers/DateTimePickerController", "moment"],
|
||||
function (DateTimePickerController, moment) {
|
||||
"use strict";
|
||||
|
||||
describe("The DateTimePickerController", function () {
|
||||
@@ -39,6 +39,14 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
function fireWatchCollection(expr, value) {
|
||||
mockScope.$watchCollection.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
@@ -57,6 +65,131 @@ define(
|
||||
);
|
||||
});
|
||||
|
||||
it("updates value in model when values in scope change", function () {
|
||||
mockScope.date = {
|
||||
year: 1998,
|
||||
month: 0,
|
||||
day: 6
|
||||
};
|
||||
mockScope.time = {
|
||||
hours: 12,
|
||||
minutes: 34,
|
||||
seconds: 56
|
||||
};
|
||||
fireWatchCollection("date", mockScope.date);
|
||||
expect(mockScope.ngModel[mockScope.field])
|
||||
.toEqual(moment.utc("1998-01-06 12:34:56").valueOf());
|
||||
});
|
||||
|
||||
describe("once initialized with model state", function () {
|
||||
var testTime = moment.utc("1998-01-06 12:34:56").valueOf();
|
||||
|
||||
beforeEach(function () {
|
||||
fireWatch("ngModel[field]", testTime);
|
||||
});
|
||||
|
||||
it("exposes date/time values in scope", function () {
|
||||
expect(mockScope.date.year).toEqual(1998);
|
||||
expect(mockScope.date.month).toEqual(0); // Months are zero-indexed
|
||||
expect(mockScope.date.day).toEqual(6);
|
||||
expect(mockScope.time.hours).toEqual(12);
|
||||
expect(mockScope.time.minutes).toEqual(34);
|
||||
expect(mockScope.time.seconds).toEqual(56);
|
||||
});
|
||||
|
||||
it("provides names for time properties", function () {
|
||||
Object.keys(mockScope.time).forEach(function (key) {
|
||||
expect(mockScope.nameFor(key))
|
||||
.toEqual(jasmine.any(String));
|
||||
});
|
||||
});
|
||||
|
||||
it("provides options for time properties", function () {
|
||||
Object.keys(mockScope.time).forEach(function (key) {
|
||||
expect(mockScope.optionsFor(key))
|
||||
.toEqual(jasmine.any(Array));
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes times to populate calendar as a table", function () {
|
||||
// Verify that data structure is as expected by template
|
||||
expect(mockScope.table).toEqual(jasmine.any(Array));
|
||||
expect(mockScope.table[0]).toEqual(jasmine.any(Array));
|
||||
expect(mockScope.table[0][0]).toEqual({
|
||||
year: jasmine.any(Number),
|
||||
month: jasmine.any(Number),
|
||||
day: jasmine.any(Number),
|
||||
dayOfYear: jasmine.any(Number)
|
||||
});
|
||||
});
|
||||
|
||||
it("contains the current date in its initial table", function () {
|
||||
var matchingCell;
|
||||
// Should be able to find the selected date
|
||||
mockScope.table.forEach(function (row) {
|
||||
row.forEach(function (cell) {
|
||||
if (cell.dayOfYear === 6) {
|
||||
matchingCell = cell;
|
||||
}
|
||||
});
|
||||
});
|
||||
expect(matchingCell).toEqual({
|
||||
year: 1998,
|
||||
month: 0,
|
||||
day: 6,
|
||||
dayOfYear: 6
|
||||
});
|
||||
});
|
||||
|
||||
it("allows the displayed month to be advanced", function () {
|
||||
// Around the edges of the displayed calendar we
|
||||
// may be in previous or subsequent month, so
|
||||
// test around the middle.
|
||||
var i, originalMonth = mockScope.table[2][0].month;
|
||||
|
||||
function mod12(month) {
|
||||
return ((month % 12) + 12) % 12;
|
||||
}
|
||||
|
||||
for (i = 1; i <= 12; i += 1) {
|
||||
mockScope.changeMonth(1);
|
||||
expect(mockScope.table[2][0].month)
|
||||
.toEqual(mod12(originalMonth + i));
|
||||
}
|
||||
|
||||
for (i = 11; i >= -12; i -= 1) {
|
||||
mockScope.changeMonth(-1);
|
||||
expect(mockScope.table[2][0].month)
|
||||
.toEqual(mod12(originalMonth + i));
|
||||
}
|
||||
});
|
||||
|
||||
it("allows checking if a cell is in the current month", function () {
|
||||
expect(mockScope.isInCurrentMonth(mockScope.table[2][0]))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("allows cells to be selected", function () {
|
||||
mockScope.select(mockScope.table[2][0]);
|
||||
expect(mockScope.isSelected(mockScope.table[2][0]))
|
||||
.toBe(true);
|
||||
mockScope.select(mockScope.table[2][1]);
|
||||
expect(mockScope.isSelected(mockScope.table[2][0]))
|
||||
.toBe(false);
|
||||
expect(mockScope.isSelected(mockScope.table[2][1]))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("allows cells to be compared", function () {
|
||||
var table = mockScope.table;
|
||||
expect(mockScope.dateEquals(table[2][0], table[2][1]))
|
||||
.toBe(false);
|
||||
expect(mockScope.dateEquals(table[2][1], table[2][1]))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* 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/controllers/SplitPaneController"],
|
||||
function (SplitPaneController) {
|
||||
"use strict";
|
||||
|
||||
describe("The split pane controller", function () {
|
||||
var controller;
|
||||
|
||||
beforeEach(function () {
|
||||
controller = new SplitPaneController();
|
||||
});
|
||||
|
||||
it("has an initial position", function () {
|
||||
expect(controller.state() > 0).toBeTruthy();
|
||||
});
|
||||
|
||||
it("can be moved", function () {
|
||||
var initialState = controller.state();
|
||||
controller.startMove();
|
||||
controller.move(50);
|
||||
expect(controller.state()).toEqual(initialState + 50);
|
||||
});
|
||||
|
||||
it("clamps its position", function () {
|
||||
var initialState = controller.state();
|
||||
controller.startMove();
|
||||
// Move some really extreme number
|
||||
controller.move(-100000);
|
||||
// Shouldn't have moved below 0...
|
||||
expect(controller.state() > 0).toBeTruthy();
|
||||
// ...but should have moved left somewhere
|
||||
expect(controller.state() < initialState).toBeTruthy();
|
||||
|
||||
// Then do the same to the right
|
||||
controller.move(100000);
|
||||
// Shouldn't have moved below 0...
|
||||
expect(controller.state() < 100000).toBeTruthy();
|
||||
// ...but should have moved left somewhere
|
||||
expect(controller.state() > initialState).toBeTruthy();
|
||||
});
|
||||
|
||||
it("accepts a default state", function () {
|
||||
// Should use default state the first time...
|
||||
expect(controller.state(12321)).toEqual(12321);
|
||||
// ...but not after it's been initialized
|
||||
expect(controller.state(42)).toEqual(12321);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -34,14 +34,14 @@ define(
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockBody,
|
||||
mockParentEl,
|
||||
mockPlainEl,
|
||||
testRect,
|
||||
mctClickElsewhere;
|
||||
|
||||
function testEvent(x, y) {
|
||||
return {
|
||||
pageX: x,
|
||||
pageY: y,
|
||||
clientX: x,
|
||||
clientY: y,
|
||||
preventDefault: jasmine.createSpy("preventDefault")
|
||||
};
|
||||
}
|
||||
@@ -55,8 +55,8 @@ define(
|
||||
jasmine.createSpyObj("element", JQLITE_METHODS);
|
||||
mockBody =
|
||||
jasmine.createSpyObj("body", JQLITE_METHODS);
|
||||
mockParentEl =
|
||||
jasmine.createSpyObj("parent", ["getBoundingClientRect"]);
|
||||
mockPlainEl =
|
||||
jasmine.createSpyObj("htmlElement", ["getBoundingClientRect"]);
|
||||
|
||||
testAttrs = {
|
||||
mctClickElsewhere: "some Angular expression"
|
||||
@@ -67,6 +67,8 @@ define(
|
||||
width: 60,
|
||||
height: 75
|
||||
};
|
||||
mockElement[0] = mockPlainEl;
|
||||
mockPlainEl.getBoundingClientRect.andReturn(testRect);
|
||||
|
||||
mockDocument.find.andReturn(mockBody);
|
||||
|
||||
@@ -78,6 +80,49 @@ define(
|
||||
expect(mctClickElsewhere.restrict).toEqual("A");
|
||||
});
|
||||
|
||||
it("detaches listeners when destroyed", function () {
|
||||
expect(mockBody.off).not.toHaveBeenCalled();
|
||||
mockScope.$on.calls.forEach(function (call) {
|
||||
if (call.args[0] === '$destroy') {
|
||||
call.args[1]();
|
||||
}
|
||||
});
|
||||
expect(mockBody.off).toHaveBeenCalled();
|
||||
expect(mockBody.off.mostRecentCall.args)
|
||||
.toEqual(mockBody.on.mostRecentCall.args);
|
||||
});
|
||||
|
||||
it("listens for mousedown on the document's body", function () {
|
||||
expect(mockBody.on)
|
||||
.toHaveBeenCalledWith('mousedown', jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe("when a click occurs outside the element's bounds", function () {
|
||||
beforeEach(function () {
|
||||
mockBody.on.mostRecentCall.args[1](testEvent(
|
||||
testRect.left + testRect.width + 10,
|
||||
testRect.top + testRect.height + 10
|
||||
));
|
||||
});
|
||||
|
||||
it("triggers an evaluation of its related Angular expression", function () {
|
||||
expect(mockScope.$eval)
|
||||
.toHaveBeenCalledWith(testAttrs.mctClickElsewhere);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when a click occurs within the element's bounds", function () {
|
||||
beforeEach(function () {
|
||||
mockBody.on.mostRecentCall.args[1](testEvent(
|
||||
testRect.left + testRect.width / 2,
|
||||
testRect.top + testRect.height / 2
|
||||
));
|
||||
});
|
||||
|
||||
it("triggers no evaluation", function () {
|
||||
expect(mockScope.$eval).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,13 +30,16 @@ define(
|
||||
'on',
|
||||
'addClass',
|
||||
'children',
|
||||
'eq'
|
||||
'eq',
|
||||
'toggleClass',
|
||||
'css'
|
||||
];
|
||||
|
||||
describe("The mct-split-pane directive", function () {
|
||||
var mockParse,
|
||||
mockLog,
|
||||
mockInterval,
|
||||
mockParsed,
|
||||
mctSplitPane;
|
||||
|
||||
beforeEach(function () {
|
||||
@@ -45,6 +48,11 @@ define(
|
||||
jasmine.createSpyObj('$log', ['warn', 'info', 'debug']);
|
||||
mockInterval = jasmine.createSpy('$interval');
|
||||
mockInterval.cancel = jasmine.createSpy('mockCancel');
|
||||
mockParsed = jasmine.createSpy('parsed');
|
||||
mockParsed.assign = jasmine.createSpy('assign');
|
||||
|
||||
mockParse.andReturn(mockParsed);
|
||||
|
||||
mctSplitPane = new MCTSplitPane(
|
||||
mockParse,
|
||||
mockLog,
|
||||
@@ -61,8 +69,19 @@ define(
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockChildren,
|
||||
mockFirstPane,
|
||||
mockSplitter,
|
||||
mockSecondPane,
|
||||
controller;
|
||||
|
||||
function fireOn(eventType) {
|
||||
mockScope.$on.calls.forEach(function (call) {
|
||||
if (call.args[0] === eventType) {
|
||||
call.args[1]();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope =
|
||||
jasmine.createSpyObj('$scope', ['$apply', '$watch', '$on']);
|
||||
@@ -71,10 +90,33 @@ define(
|
||||
testAttrs = {};
|
||||
mockChildren =
|
||||
jasmine.createSpyObj('children', JQLITE_METHODS);
|
||||
mockFirstPane =
|
||||
jasmine.createSpyObj('firstPane', JQLITE_METHODS);
|
||||
mockSplitter =
|
||||
jasmine.createSpyObj('splitter', JQLITE_METHODS);
|
||||
mockSecondPane =
|
||||
jasmine.createSpyObj('secondPane', JQLITE_METHODS);
|
||||
|
||||
mockElement.children.andReturn(mockChildren);
|
||||
mockChildren.eq.andReturn(mockChildren);
|
||||
mockChildren[0] = {};
|
||||
mockElement[0] = {
|
||||
offsetWidth: 12321,
|
||||
offsetHeight: 45654
|
||||
};
|
||||
mockChildren.eq.andCallFake(function (i) {
|
||||
return [mockFirstPane, mockSplitter, mockSecondPane][i];
|
||||
});
|
||||
mockFirstPane[0] = { offsetWidth: 123, offsetHeight: 456 };
|
||||
mockSplitter[0] = {
|
||||
nodeName: 'mct-splitter',
|
||||
offsetWidth: 10,
|
||||
offsetHeight: 456
|
||||
};
|
||||
mockSecondPane[0] = { offsetWidth: 10, offsetHeight: 456 };
|
||||
|
||||
mockChildren[0] = mockFirstPane[0];
|
||||
mockChildren[1] = mockSplitter[0];
|
||||
mockChildren[3] = mockSecondPane[0];
|
||||
mockChildren.length = 3;
|
||||
|
||||
controller = mctSplitPane.controller[3](
|
||||
mockScope,
|
||||
@@ -87,6 +129,77 @@ define(
|
||||
expect(mockInterval.mostRecentCall.args[3]).toBe(false);
|
||||
});
|
||||
|
||||
it("exposes its splitter's initial position", function () {
|
||||
expect(controller.position()).toEqual(
|
||||
mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
|
||||
);
|
||||
});
|
||||
|
||||
it("exposes the current anchoring mode", function () {
|
||||
expect(controller.anchor()).toEqual({
|
||||
edge : 'left',
|
||||
opposite : 'right',
|
||||
dimension : 'width',
|
||||
orientation : 'vertical'
|
||||
});
|
||||
});
|
||||
|
||||
it("allows classes to be toggled on contained elements", function () {
|
||||
controller.toggleClass('resizing');
|
||||
expect(mockChildren.toggleClass)
|
||||
.toHaveBeenCalledWith('resizing');
|
||||
});
|
||||
|
||||
it("allows positions to be set", function () {
|
||||
var testValue = mockChildren[0].offsetWidth + 50;
|
||||
controller.position(testValue);
|
||||
expect(mockFirstPane.css).toHaveBeenCalledWith(
|
||||
'width',
|
||||
(testValue - mockSplitter[0].offsetWidth) + 'px'
|
||||
);
|
||||
});
|
||||
|
||||
it("issues no warnings under nominal usage", function () {
|
||||
expect(mockLog.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("warns if no mct-splitter is present", function () {
|
||||
mockSplitter[0].nodeName = "not-mct-splitter";
|
||||
controller = mctSplitPane.controller[3](
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs
|
||||
);
|
||||
expect(mockLog.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("warns if an unknown anchor key is given", function () {
|
||||
testAttrs.anchor = "middle";
|
||||
controller = mctSplitPane.controller[3](
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs
|
||||
);
|
||||
expect(mockLog.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("updates positions on a timer", function () {
|
||||
mockFirstPane[0].offsetWidth += 100;
|
||||
// Should not reflect the change yet
|
||||
expect(controller.position()).not.toEqual(
|
||||
mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
|
||||
);
|
||||
mockInterval.mostRecentCall.args[0]();
|
||||
expect(controller.position()).toEqual(
|
||||
mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
|
||||
);
|
||||
});
|
||||
|
||||
it("cancels the active interval when scope is destroyed", function () {
|
||||
expect(mockInterval.cancel).not.toHaveBeenCalled();
|
||||
fireOn('$destroy');
|
||||
expect(mockInterval.cancel).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
113
platform/commonUI/general/test/directives/MCTSplitterSpec.js
Normal file
113
platform/commonUI/general/test/directives/MCTSplitterSpec.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/*****************************************************************************
|
||||
* 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/directives/MCTSplitter"],
|
||||
function (MCTSplitter) {
|
||||
'use strict';
|
||||
|
||||
describe("The mct-splitter directive", function () {
|
||||
var mctSplitter;
|
||||
|
||||
beforeEach(function () {
|
||||
mctSplitter = new MCTSplitter();
|
||||
});
|
||||
|
||||
it("is applicable to elements", function () {
|
||||
expect(mctSplitter.restrict).toEqual("E");
|
||||
});
|
||||
|
||||
it("depends on the mct-split-pane controller", function () {
|
||||
expect(mctSplitter.require).toEqual("^mctSplitPane");
|
||||
});
|
||||
|
||||
describe("when linked", function () {
|
||||
var mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockSplitPane;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
'$scope',
|
||||
[ '$on', '$watch' ]
|
||||
);
|
||||
mockElement = jasmine.createSpyObj(
|
||||
'element',
|
||||
[ 'addClass' ]
|
||||
);
|
||||
testAttrs = {};
|
||||
mockSplitPane = jasmine.createSpyObj(
|
||||
'mctSplitPane',
|
||||
[ 'position', 'toggleClass', 'anchor' ]
|
||||
);
|
||||
|
||||
mctSplitter.link(
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockSplitPane
|
||||
);
|
||||
});
|
||||
|
||||
it("adds a splitter class", function () {
|
||||
expect(mockElement.addClass)
|
||||
.toHaveBeenCalledWith('splitter');
|
||||
});
|
||||
|
||||
describe("and then manipulated", function () {
|
||||
var testPosition;
|
||||
|
||||
beforeEach(function () {
|
||||
testPosition = 12321;
|
||||
mockSplitPane.position.andReturn(testPosition);
|
||||
mockSplitPane.anchor.andReturn({
|
||||
orientation: 'vertical',
|
||||
reversed: false
|
||||
});
|
||||
mockScope.splitter.startMove();
|
||||
});
|
||||
|
||||
it("adds a 'resizing' class", function () {
|
||||
expect(mockSplitPane.toggleClass)
|
||||
.toHaveBeenCalledWith('resizing');
|
||||
});
|
||||
|
||||
it("repositions during drag", function () {
|
||||
mockScope.splitter.move([ 10, 0 ]);
|
||||
expect(mockSplitPane.position)
|
||||
.toHaveBeenCalledWith(testPosition + 10);
|
||||
});
|
||||
|
||||
it("removes the 'resizing' class when finished", function () {
|
||||
mockSplitPane.toggleClass.reset();
|
||||
mockScope.splitter.endMove();
|
||||
expect(mockSplitPane.toggleClass)
|
||||
.toHaveBeenCalledWith('resizing');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -8,7 +8,6 @@
|
||||
"controllers/GetterSetterController",
|
||||
"controllers/ObjectInspectorController",
|
||||
"controllers/SelectorController",
|
||||
"controllers/SplitPaneController",
|
||||
"controllers/TimeRangeController",
|
||||
"controllers/ToggleController",
|
||||
"controllers/TreeNodeController",
|
||||
@@ -20,6 +19,7 @@
|
||||
"directives/MCTResize",
|
||||
"directives/MCTScroll",
|
||||
"directives/MCTSplitPane",
|
||||
"directives/MCTSplitter",
|
||||
"services/Popup",
|
||||
"services/PopupService",
|
||||
"services/UrlService",
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
"implementation": "AgentService.js",
|
||||
"depends": [ "$window" ]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"implementation": "DeviceClassifier.js",
|
||||
"depends": [ "agentService", "$document" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ define(
|
||||
this.userAgent = userAgent;
|
||||
this.mobileName = matches[0];
|
||||
this.$window = $window;
|
||||
this.touchEnabled = ($window.ontouchstart !== undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +93,14 @@ define(
|
||||
return !this.isPortrait();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the user's device supports a touch interface.
|
||||
* @returns {boolean} true if touch is supported
|
||||
*/
|
||||
AgentService.prototype.isTouch = function () {
|
||||
return this.touchEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the user agent matches a certain named device,
|
||||
* as indicated by checking for a case-insensitive substring
|
||||
|
||||
59
platform/commonUI/mobile/src/DeviceClassifier.js
Normal file
59
platform/commonUI/mobile/src/DeviceClassifier.js
Normal file
@@ -0,0 +1,59 @@
|
||||
/*****************************************************************************
|
||||
* 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*/
|
||||
|
||||
define(
|
||||
['./DeviceMatchers'],
|
||||
function (DeviceMatchers) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Runs at application startup and adds a subset of the following
|
||||
* CSS classes to the body of the document, depending on device
|
||||
* attributes:
|
||||
*
|
||||
* * `mobile`: Phones or tablets.
|
||||
* * `phone`: Phones specifically.
|
||||
* * `tablet`: Tablets specifically.
|
||||
* * `desktop`: Non-mobile devices.
|
||||
* * `portrait`: Devices in a portrait-style orientation.
|
||||
* * `landscape`: Devices in a landscape-style orientation.
|
||||
* * `touch`: Device supports touch events.
|
||||
*
|
||||
* @param {platform/commonUI/mobile.AgentService} agentService
|
||||
* the service used to examine the user agent
|
||||
* @param $document Angular's jqLite-wrapped document element
|
||||
* @constructor
|
||||
*/
|
||||
function MobileClassifier(agentService, $document) {
|
||||
var body = $document.find('body');
|
||||
Object.keys(DeviceMatchers).forEach(function (key) {
|
||||
if (DeviceMatchers[key](agentService)) {
|
||||
body.addClass(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return MobileClassifier;
|
||||
|
||||
}
|
||||
);
|
||||
60
platform/commonUI/mobile/src/DeviceMatchers.js
Normal file
60
platform/commonUI/mobile/src/DeviceMatchers.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/*****************************************************************************
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* An object containing key-value pairs, where keys are symbolic of
|
||||
* device attributes, and values are functions that take the
|
||||
* `agentService` as inputs and return boolean values indicating
|
||||
* whether or not the current device has these attributes.
|
||||
*
|
||||
* For internal use by the mobile support bundle.
|
||||
*
|
||||
* @memberof platform/commonUI/mobile
|
||||
* @private
|
||||
*/
|
||||
return {
|
||||
mobile: function (agentService) {
|
||||
return agentService.isMobile();
|
||||
},
|
||||
phone: function (agentService) {
|
||||
return agentService.isPhone();
|
||||
},
|
||||
tablet: function (agentService) {
|
||||
return agentService.isTablet();
|
||||
},
|
||||
desktop: function (agentService) {
|
||||
return !agentService.isMobile();
|
||||
},
|
||||
portrait: function (agentService) {
|
||||
return agentService.isPortrait();
|
||||
},
|
||||
landscape: function (agentService) {
|
||||
return agentService.isLandscape();
|
||||
},
|
||||
touch: function (agentService) {
|
||||
return agentService.isTouch();
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -22,31 +22,10 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
define(
|
||||
function () {
|
||||
['./DeviceMatchers'],
|
||||
function (DeviceMatchers) {
|
||||
'use strict';
|
||||
|
||||
var DEVICE_MATCHERS = {
|
||||
mobile: function (agentService) {
|
||||
return agentService.isMobile();
|
||||
},
|
||||
phone: function (agentService) {
|
||||
return agentService.isPhone();
|
||||
},
|
||||
tablet: function (agentService) {
|
||||
return agentService.isTablet();
|
||||
},
|
||||
desktop: function (agentService) {
|
||||
return !agentService.isMobile();
|
||||
},
|
||||
portrait: function (agentService) {
|
||||
return agentService.isPortrait();
|
||||
},
|
||||
landscape: function (agentService) {
|
||||
return agentService.isLandscape();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The `mct-device` directive, when applied as an attribute,
|
||||
* only includes the element when the device being used matches
|
||||
@@ -68,6 +47,7 @@ define(
|
||||
* * `desktop`: Non-mobile devices.
|
||||
* * `portrait`: Devices in a portrait-style orientation.
|
||||
* * `landscape`: Devices in a landscape-style orientation.
|
||||
* * `touch`: Device supports touch events.
|
||||
*
|
||||
* @param {AgentService} agentService used to detect device type
|
||||
* based on information about the user agent
|
||||
@@ -77,7 +57,7 @@ define(
|
||||
function deviceMatches(tokens) {
|
||||
tokens = tokens || "";
|
||||
return tokens.split(" ").every(function (token) {
|
||||
var fn = DEVICE_MATCHERS[token];
|
||||
var fn = DeviceMatchers[token];
|
||||
return fn && fn(agentService);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -82,6 +82,15 @@ define(
|
||||
expect(agentService.isLandscape()).toBeFalsy();
|
||||
});
|
||||
|
||||
it("detects touch support", function () {
|
||||
testWindow.ontouchstart = null;
|
||||
expect(new AgentService(testWindow).isTouch())
|
||||
.toBe(true);
|
||||
delete testWindow.ontouchstart;
|
||||
expect(new AgentService(testWindow).isTouch())
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
it("allows for checking browser type", function () {
|
||||
testWindow.navigator.userAgent = "Chromezilla Safarifox";
|
||||
agentService = new AgentService(testWindow);
|
||||
|
||||
112
platform/commonUI/mobile/test/DeviceClassifierSpec.js
Normal file
112
platform/commonUI/mobile/test/DeviceClassifierSpec.js
Normal file
@@ -0,0 +1,112 @@
|
||||
/*****************************************************************************
|
||||
* 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/DeviceClassifier", "../src/DeviceMatchers"],
|
||||
function (DeviceClassifier, DeviceMatchers) {
|
||||
"use strict";
|
||||
|
||||
var AGENT_SERVICE_METHODS = [
|
||||
'isMobile',
|
||||
'isPhone',
|
||||
'isTablet',
|
||||
'isPortrait',
|
||||
'isLandscape',
|
||||
'isTouch'
|
||||
],
|
||||
TEST_PERMUTATIONS = [
|
||||
[ 'isMobile', 'isPhone', 'isTouch', 'isPortrait' ],
|
||||
[ 'isMobile', 'isPhone', 'isTouch', 'isLandscape' ],
|
||||
[ 'isMobile', 'isTablet', 'isTouch', 'isPortrait' ],
|
||||
[ 'isMobile', 'isTablet', 'isTouch', 'isLandscape' ],
|
||||
[ 'isTouch' ],
|
||||
[]
|
||||
];
|
||||
|
||||
describe("DeviceClassifier", function () {
|
||||
var mockAgentService,
|
||||
mockDocument,
|
||||
mockBody;
|
||||
|
||||
beforeEach(function () {
|
||||
mockAgentService = jasmine.createSpyObj(
|
||||
'agentService',
|
||||
AGENT_SERVICE_METHODS
|
||||
);
|
||||
mockDocument = jasmine.createSpyObj(
|
||||
'$document',
|
||||
[ 'find' ]
|
||||
);
|
||||
mockBody = jasmine.createSpyObj(
|
||||
'body',
|
||||
[ 'addClass' ]
|
||||
);
|
||||
mockDocument.find.andCallFake(function (sel) {
|
||||
return sel === 'body' && mockBody;
|
||||
});
|
||||
AGENT_SERVICE_METHODS.forEach(function (m) {
|
||||
mockAgentService[m].andReturn(false);
|
||||
});
|
||||
});
|
||||
|
||||
TEST_PERMUTATIONS.forEach(function (trueMethods) {
|
||||
var summary = trueMethods.length === 0 ?
|
||||
"device has no detected characteristics" :
|
||||
"device " + (trueMethods.join(", "));
|
||||
|
||||
describe("when " + summary, function () {
|
||||
var classifier;
|
||||
|
||||
beforeEach(function () {
|
||||
trueMethods.forEach(function (m) {
|
||||
mockAgentService[m].andReturn(true);
|
||||
});
|
||||
classifier = new DeviceClassifier(
|
||||
mockAgentService,
|
||||
mockDocument
|
||||
);
|
||||
});
|
||||
|
||||
it("adds classes for matching, detected characteristics", function () {
|
||||
Object.keys(DeviceMatchers).filter(function (m) {
|
||||
return DeviceMatchers[m](mockAgentService);
|
||||
}).forEach(function (key) {
|
||||
expect(mockBody.addClass)
|
||||
.toHaveBeenCalledWith(key);
|
||||
});
|
||||
});
|
||||
|
||||
it("does not add classes for non-matching characteristics", function () {
|
||||
Object.keys(DeviceMatchers).filter(function (m) {
|
||||
return !DeviceMatchers[m](mockAgentService);
|
||||
}).forEach(function (key) {
|
||||
expect(mockBody.addClass)
|
||||
.not.toHaveBeenCalledWith(key);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
81
platform/commonUI/mobile/test/DeviceMatchersSpec.js
Normal file
81
platform/commonUI/mobile/test/DeviceMatchersSpec.js
Normal file
@@ -0,0 +1,81 @@
|
||||
/*****************************************************************************
|
||||
* 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/DeviceMatchers"],
|
||||
function (DeviceMatchers) {
|
||||
'use strict';
|
||||
|
||||
describe("DeviceMatchers", function () {
|
||||
var mockAgentService;
|
||||
|
||||
beforeEach(function () {
|
||||
mockAgentService = jasmine.createSpyObj(
|
||||
'agentService',
|
||||
[
|
||||
'isMobile',
|
||||
'isPhone',
|
||||
'isTablet',
|
||||
'isPortrait',
|
||||
'isLandscape',
|
||||
'isTouch'
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it("detects when a device is a desktop device", function () {
|
||||
mockAgentService.isMobile.andReturn(false);
|
||||
expect(DeviceMatchers.desktop(mockAgentService))
|
||||
.toBe(true);
|
||||
mockAgentService.isMobile.andReturn(true);
|
||||
expect(DeviceMatchers.desktop(mockAgentService))
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
function method(deviceType) {
|
||||
return "is" + deviceType[0].toUpperCase() + deviceType.slice(1);
|
||||
}
|
||||
|
||||
[
|
||||
"mobile",
|
||||
"phone",
|
||||
"tablet",
|
||||
"landscape",
|
||||
"portrait",
|
||||
"landscape",
|
||||
"touch"
|
||||
].forEach(function (deviceType) {
|
||||
it("detects when a device is a " + deviceType + " device", function () {
|
||||
mockAgentService[method(deviceType)].andReturn(true);
|
||||
expect(DeviceMatchers[deviceType](mockAgentService))
|
||||
.toBe(true);
|
||||
mockAgentService[method(deviceType)].andReturn(false);
|
||||
expect(DeviceMatchers[deviceType](mockAgentService))
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,4 +1,6 @@
|
||||
[
|
||||
"AgentService",
|
||||
"DeviceClassifier",
|
||||
"DeviceMatchers",
|
||||
"MCTDevice"
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user