Merged conflict
This commit is contained in:
@@ -24,7 +24,9 @@
|
||||
<ul class="tree">
|
||||
<li ng-repeat="containedObject in composition">
|
||||
<span class="tree-item">
|
||||
<mct-representation key="'label'" mct-object="containedObject">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="containedObject"
|
||||
class="rep-object-label">
|
||||
</mct-representation>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,12 +84,20 @@
|
||||
}
|
||||
|
||||
.inspector-location {
|
||||
//line-height: 180%;
|
||||
.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;
|
||||
@@ -104,6 +112,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";
|
||||
|
||||
@@ -300,7 +300,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 {
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
left: $interiorMarginSm;
|
||||
@include trans-prop-nice(color, 250ms);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
// Make icon lighten when hovering over search bar
|
||||
@@ -127,7 +128,7 @@
|
||||
}
|
||||
|
||||
.active-filter-display {
|
||||
$s: 0.65em;
|
||||
$s: 0.7em;
|
||||
$p: $interiorMargin;
|
||||
@include box-sizing(border-box);
|
||||
line-height: 130%;
|
||||
@@ -146,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,8 +124,28 @@ ul.tree {
|
||||
}
|
||||
}
|
||||
|
||||
.tree-item {
|
||||
.t-object-label {
|
||||
left: $interiorMargin + $treeVCW;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
.splitter-treeview,
|
||||
.holder-treeview-elements {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,6 +305,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>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
class="location-item rep-object-label">
|
||||
</mct-representation>
|
||||
</span>
|
||||
</li>
|
||||
@@ -54,7 +54,7 @@
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
class="location-item rep-object-label">
|
||||
</mct-representation>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
@@ -26,41 +26,18 @@
|
||||
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"
|
||||
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"
|
||||
]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,7 @@ define(
|
||||
this.policyService = policyService;
|
||||
this.persisted = 0;
|
||||
this.clones = [];
|
||||
this.idMap = {};
|
||||
}
|
||||
|
||||
function composeChild(child, parent, setLocation) {
|
||||
@@ -57,6 +58,8 @@ define(
|
||||
if (setLocation && child.getModel().location === undefined) {
|
||||
child.getModel().location = parent.getId();
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
function cloneObjectModel(objectModel) {
|
||||
@@ -104,6 +107,35 @@ define(
|
||||
.then(function(){return self.firstClone;});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update identifiers in a cloned object model (or part of
|
||||
* a cloned object model) to reflect new identifiers after
|
||||
* copying.
|
||||
* @private
|
||||
*/
|
||||
CopyTask.prototype.rewriteIdentifiers = function (obj, idMap) {
|
||||
function lookupValue(value) {
|
||||
return (typeof value === 'string' && idMap[value]) || value;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
obj.forEach(function (value, index) {
|
||||
obj[index] = lookupValue(value);
|
||||
this.rewriteIdentifiers(obj[index], idMap);
|
||||
}, this);
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
Object.keys(obj).forEach(function (key) {
|
||||
var value = obj[key];
|
||||
obj[key] = lookupValue(value);
|
||||
if (idMap[key]) {
|
||||
delete obj[key];
|
||||
obj[idMap[key]] = value;
|
||||
}
|
||||
this.rewriteIdentifiers(value, idMap);
|
||||
}, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an array of objects composed by a parent, clone them, then
|
||||
* add them to the parent.
|
||||
@@ -111,7 +143,8 @@ define(
|
||||
* @returns {*}
|
||||
*/
|
||||
CopyTask.prototype.copyComposees = function(composees, clonedParent, originalParent){
|
||||
var self = this;
|
||||
var self = this,
|
||||
idMap = {};
|
||||
|
||||
return (composees || []).reduce(function(promise, originalComposee){
|
||||
//If the composee is composed of other
|
||||
@@ -119,13 +152,28 @@ define(
|
||||
return promise.then(function(){
|
||||
// ...to recursively copy it (and its children)
|
||||
return self.copy(originalComposee, originalParent).then(function(clonedComposee){
|
||||
//Map the original composee's ID to that of its
|
||||
// clone so that we can replace any references to it
|
||||
// in the parent
|
||||
idMap[originalComposee.getId()] = clonedComposee.getId();
|
||||
|
||||
//Compose the child within its parent. Cloned
|
||||
// objects will need to also have their location
|
||||
// set, however linked objects will not.
|
||||
return composeChild(clonedComposee, clonedParent, clonedComposee !== originalComposee);
|
||||
});
|
||||
});}, self.$q.when(undefined)
|
||||
);
|
||||
).then(function(){
|
||||
//Replace any references in the cloned parent to
|
||||
// contained objects that have been composed with the
|
||||
// Ids of the clones
|
||||
self.rewriteIdentifiers(clonedParent.getModel(), idMap);
|
||||
|
||||
//Add the clone to the list of clones that will
|
||||
//be returned by this function
|
||||
self.clones.push(clonedParent);
|
||||
return clonedParent;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -159,12 +207,7 @@ define(
|
||||
//Duplicate the object's children, and their children, and
|
||||
// so on down to the leaf nodes of the tree.
|
||||
//If it is a link, don't both with children
|
||||
return self.copyComposees(composees, clone, originalObject).then(function (){
|
||||
//Add the clone to the list of clones that will
|
||||
//be returned by this function
|
||||
self.clones.push(clone);
|
||||
return clone;
|
||||
});
|
||||
return self.copyComposees(composees, clone, originalObject);
|
||||
});
|
||||
} else {
|
||||
//Creating a link, no need to iterate children
|
||||
|
||||
277
platform/entanglement/test/services/CopyTaskSpec.js
Normal file
277
platform/entanglement/test/services/CopyTaskSpec.js
Normal file
@@ -0,0 +1,277 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,beforeEach,it,jasmine,expect,spyOn */
|
||||
|
||||
define(
|
||||
[
|
||||
'../../src/services/CopyTask',
|
||||
'../DomainObjectFactory'
|
||||
],
|
||||
function (CopyTask, domainObjectFactory) {
|
||||
'use strict';
|
||||
|
||||
var ID_A = "some-string-with-vaguely-uuidish-uniqueness",
|
||||
ID_B = "some-other-similarly-unique-string";
|
||||
|
||||
function synchronousPromise(value) {
|
||||
return (value && value.then) ? value : {
|
||||
then: function (callback) {
|
||||
return synchronousPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("CopyTask", function () {
|
||||
var mockDomainObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockQ,
|
||||
mockDeferred,
|
||||
testModel,
|
||||
mockCallback,
|
||||
counter,
|
||||
cloneIds,
|
||||
task;
|
||||
|
||||
function makeMockCapabilities(childIds) {
|
||||
var mockCapabilities = {
|
||||
persistence: jasmine.createSpyObj(
|
||||
'persistence',
|
||||
['persist']
|
||||
),
|
||||
composition: jasmine.createSpyObj(
|
||||
'composition',
|
||||
['add', 'invoke']
|
||||
),
|
||||
instantiation: jasmine.createSpyObj(
|
||||
'instantiation',
|
||||
['instantiate', 'invoke']
|
||||
)
|
||||
},
|
||||
mockChildren = (childIds || []).map(function (id) {
|
||||
return domainObjectFactory({
|
||||
id: id,
|
||||
capabilities: makeMockCapabilities([]),
|
||||
model: { originalId: id }
|
||||
});
|
||||
});
|
||||
|
||||
mockCapabilities.persistence.persist
|
||||
.andReturn(synchronousPromise(true));
|
||||
mockCapabilities.composition.add.andCallFake(function (obj) {
|
||||
return synchronousPromise(obj);
|
||||
});
|
||||
mockCapabilities.composition.invoke
|
||||
.andReturn(synchronousPromise(mockChildren));
|
||||
mockCapabilities.instantiation.invoke
|
||||
.andCallFake(function (model) {
|
||||
var id = "some-id-" + counter;
|
||||
cloneIds[model.originalId] = id;
|
||||
counter += 1;
|
||||
return domainObjectFactory({
|
||||
id: id,
|
||||
model: model,
|
||||
capabilities: makeMockCapabilities()
|
||||
});
|
||||
});
|
||||
|
||||
return mockCapabilities;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
counter = 0;
|
||||
cloneIds = {};
|
||||
|
||||
testModel = {
|
||||
composition: [ ID_A, ID_B ],
|
||||
someObj: {},
|
||||
someArr: [ ID_A, ID_B ],
|
||||
objArr: [{"id": ID_A}, {"id": ID_B}],
|
||||
singleElementArr: [ ID_A ]
|
||||
};
|
||||
testModel.someObj[ID_A] = "some value";
|
||||
testModel.someObj.someProperty = ID_B;
|
||||
|
||||
mockDomainObject = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities(testModel.composition),
|
||||
model: testModel
|
||||
});
|
||||
mockParentObject = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities()
|
||||
});
|
||||
mockPolicyService = jasmine.createSpyObj(
|
||||
'policyService',
|
||||
[ 'allow' ]
|
||||
);
|
||||
mockQ = jasmine.createSpyObj('$q', ['when', 'defer', 'all']);
|
||||
mockDeferred = jasmine.createSpyObj(
|
||||
'deferred',
|
||||
[ 'notify', 'resolve', 'reject' ]
|
||||
);
|
||||
|
||||
mockPolicyService.allow.andReturn(true);
|
||||
|
||||
mockQ.when.andCallFake(synchronousPromise);
|
||||
mockQ.defer.andReturn(mockDeferred);
|
||||
mockQ.all.andCallFake(function (promises) {
|
||||
return synchronousPromise(promises.map(function (promise) {
|
||||
var value;
|
||||
promise.then(function (v) { value = v; });
|
||||
return value;
|
||||
}));
|
||||
});
|
||||
|
||||
mockDeferred.resolve.andCallFake(function (value) {
|
||||
mockDeferred.promise = synchronousPromise(value);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("produces models which", function () {
|
||||
var model;
|
||||
|
||||
beforeEach(function () {
|
||||
task = new CopyTask(
|
||||
mockDomainObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockQ
|
||||
);
|
||||
|
||||
task.perform().then(function (clone) {
|
||||
model = clone.getModel();
|
||||
});
|
||||
});
|
||||
|
||||
it("contain rewritten identifiers in arrays", function () {
|
||||
expect(model.someArr)
|
||||
.toEqual(testModel.someArr.map(function (id) {
|
||||
return cloneIds[id];
|
||||
}));
|
||||
});
|
||||
|
||||
it("contain rewritten identifiers in properties", function () {
|
||||
expect(model.someObj.someProperty)
|
||||
.toEqual(cloneIds[testModel.someObj.someProperty]);
|
||||
});
|
||||
|
||||
|
||||
it("contain rewritten identifiers in property names", function () {
|
||||
expect(model.someObj[cloneIds[ID_A]])
|
||||
.toEqual(testModel.someObj[ID_A]);
|
||||
});
|
||||
|
||||
it("contain rewritten identifiers in single-element arrays", function () {
|
||||
expect(model.singleElementArr)
|
||||
.toEqual(testModel.singleElementArr.map(function (id) {
|
||||
return cloneIds[id];
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("copies object trees with multiple references to the" +
|
||||
" same object", function () {
|
||||
var model,
|
||||
mockDomainObjectB,
|
||||
mockComposingObject,
|
||||
composingObjectModel,
|
||||
domainObjectClone,
|
||||
domainObjectBClone;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObjectB = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities(testModel.composition),
|
||||
model: testModel
|
||||
});
|
||||
composingObjectModel = {
|
||||
name: 'mockComposingObject',
|
||||
composition: [mockDomainObject.getId(), mockDomainObjectB.getId()]
|
||||
};
|
||||
mockComposingObject = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities(composingObjectModel.composition),
|
||||
model: composingObjectModel
|
||||
});
|
||||
|
||||
mockComposingObject.capabilities.composition.invoke.andReturn([mockDomainObject, mockDomainObjectB]);
|
||||
task = new CopyTask(
|
||||
mockComposingObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockQ
|
||||
);
|
||||
|
||||
task.perform();
|
||||
domainObjectClone = task.clones[2];
|
||||
domainObjectBClone = task.clones[5];
|
||||
});
|
||||
|
||||
/**
|
||||
* mockDomainObject and mockDomainObjectB have the same
|
||||
* model with references to children ID_A and ID_B. Expect
|
||||
* that after duplication the references should differ
|
||||
* because they are each now referencing different child
|
||||
* objects. This tests the issue reported in #428
|
||||
*/
|
||||
it(" and correctly updates child identifiers in models ", function () {
|
||||
var childA_ID = task.clones[0].getId(),
|
||||
childB_ID = task.clones[1].getId(),
|
||||
childC_ID = task.clones[3].getId(),
|
||||
childD_ID = task.clones[4].getId();
|
||||
|
||||
expect(domainObjectClone.model.someArr[0]).toNotBe(domainObjectBClone.model.someArr[0]);
|
||||
expect(domainObjectClone.model.someArr[0]).toBe(childA_ID);
|
||||
expect(domainObjectBClone.model.someArr[0]).toBe(childC_ID);
|
||||
expect(domainObjectClone.model.someArr[1]).toNotBe(domainObjectBClone.model.someArr[1]);
|
||||
expect(domainObjectClone.model.someArr[1]).toBe(childB_ID);
|
||||
expect(domainObjectBClone.model.someArr[1]).toBe(childD_ID);
|
||||
expect(domainObjectClone.model.someObj.someProperty).toNotBe(domainObjectBClone.model.someObj.someProperty);
|
||||
expect(domainObjectClone.model.someObj.someProperty).toBe(childB_ID);
|
||||
expect(domainObjectBClone.model.someObj.someProperty).toBe(childD_ID);
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* This a bug found in testathon when testing issue #428
|
||||
*/
|
||||
it(" and correctly updates child identifiers in object" +
|
||||
" arrays within models ", function () {
|
||||
var childA_ID = task.clones[0].getId(),
|
||||
childB_ID = task.clones[1].getId(),
|
||||
childC_ID = task.clones[3].getId(),
|
||||
childD_ID = task.clones[4].getId();
|
||||
|
||||
expect(domainObjectClone.model.objArr[0].id).not.toBe(ID_A);
|
||||
expect(domainObjectClone.model.objArr[0].id).toBe(childA_ID);
|
||||
expect(domainObjectClone.model.objArr[1].id).not.toBe(ID_B);
|
||||
expect(domainObjectClone.model.objArr[1].id).toBe(childB_ID);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
@@ -7,6 +7,7 @@
|
||||
"actions/SetPrimaryLocationAction",
|
||||
"policies/CrossSpacePolicy",
|
||||
"services/CopyService",
|
||||
"services/CopyTask",
|
||||
"services/LinkService",
|
||||
"services/MoveService",
|
||||
"services/LocationService",
|
||||
|
||||
@@ -423,6 +423,95 @@ define(
|
||||
// Style should have been updated
|
||||
expect(controller.selected().style).not.toEqual(oldStyle);
|
||||
});
|
||||
|
||||
describe("on display bounds changes", function () {
|
||||
var testBounds;
|
||||
|
||||
beforeEach(function () {
|
||||
testBounds = { start: 123, end: 321 };
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.model = testModel;
|
||||
findWatch("domainObject")(mockDomainObject);
|
||||
findWatch("model.modified")(testModel.modified);
|
||||
findWatch("model.composition")(mockScope.model.composition);
|
||||
findOn('telemetry:display:bounds')({}, testBounds);
|
||||
});
|
||||
|
||||
it("issues new requests", function () {
|
||||
expect(mockHandle.request).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("requests only a single point", function () {
|
||||
expect(mockHandle.request.mostRecentCall.args[0].size)
|
||||
.toEqual(1);
|
||||
});
|
||||
|
||||
describe("and after data has been received", function () {
|
||||
var mockSeries,
|
||||
testValue;
|
||||
|
||||
beforeEach(function () {
|
||||
testValue = 12321;
|
||||
|
||||
mockSeries = jasmine.createSpyObj('series', [
|
||||
'getPointCount',
|
||||
'getDomainValue',
|
||||
'getRangeValue'
|
||||
]);
|
||||
mockSeries.getPointCount.andReturn(1);
|
||||
mockSeries.getRangeValue.andReturn(testValue);
|
||||
|
||||
// Fire the callback associated with the request
|
||||
mockHandle.request.mostRecentCall.args[1](
|
||||
mockHandle.getTelemetryObjects()[0],
|
||||
mockSeries
|
||||
);
|
||||
});
|
||||
|
||||
it("updates displayed values", function () {
|
||||
expect(controller.getElements()[0].value)
|
||||
.toEqual("Formatted " + testValue);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("reflects limit status", function () {
|
||||
var elements;
|
||||
|
||||
mockHandle.getDatum.andReturn({});
|
||||
mockHandle.getTelemetryObjects().forEach(function (mockObject) {
|
||||
var id = mockObject.getId(),
|
||||
mockLimitCapability =
|
||||
jasmine.createSpyObj('limit-' + id, ['evaluate']);
|
||||
|
||||
mockObject.getCapability.andCallFake(function (key) {
|
||||
return (key === 'limit') && mockLimitCapability;
|
||||
});
|
||||
|
||||
mockLimitCapability.evaluate
|
||||
.andReturn({ cssClass: 'alarm-' + id });
|
||||
});
|
||||
|
||||
// Initialize
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.model = testModel;
|
||||
findWatch("domainObject")(mockDomainObject);
|
||||
findWatch("model.modified")(1);
|
||||
findWatch("model.composition")(mockScope.model.composition);
|
||||
|
||||
// Invoke the subscription callback
|
||||
mockHandler.handle.mostRecentCall.args[1]();
|
||||
|
||||
// Get elements that controller is now exposing
|
||||
elements = controller.getElements();
|
||||
|
||||
// Limit-based CSS classes should be available
|
||||
expect(elements[0].cssClass).toEqual("alarm-a");
|
||||
expect(elements[1].cssClass).toEqual("alarm-b");
|
||||
expect(elements[2].cssClass).toEqual("alarm-c");
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -285,6 +285,61 @@ define(
|
||||
fireWatch("axes[1].active.key", 'someNewKey');
|
||||
expect(mockHandle.request.calls.length).toEqual(2);
|
||||
});
|
||||
|
||||
|
||||
it("maintains externally-provided domain axis bounds after data is received", function () {
|
||||
mockSeries.getPointCount.andReturn(3);
|
||||
mockSeries.getRangeValue.andReturn(42);
|
||||
mockSeries.getDomainValue.andCallFake(function (i) {
|
||||
return 2500 + i * 2500;
|
||||
});
|
||||
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
fireEvent("telemetry:display:bounds", [
|
||||
{},
|
||||
{start: 0, end: 10000}
|
||||
]);
|
||||
mockHandle.request.mostRecentCall.args[1](
|
||||
mockDomainObject,
|
||||
mockSeries
|
||||
);
|
||||
|
||||
// Pan-zoom state should reflect bounds set externally;
|
||||
// domain axis should not have shrunk to fit data.
|
||||
expect(
|
||||
controller.getSubPlots()[0].panZoomStack.getOrigin()[0]
|
||||
).toEqual(0);
|
||||
expect(
|
||||
controller.getSubPlots()[0].panZoomStack.getDimensions()[0]
|
||||
).toEqual(10000);
|
||||
});
|
||||
|
||||
it("provides classes for legends based on limit state", function () {
|
||||
var mockTelemetryObjects = mockHandle.getTelemetryObjects();
|
||||
|
||||
mockHandle.getDatum.andReturn({});
|
||||
mockTelemetryObjects.forEach(function (mockObject, i) {
|
||||
var id = 'object-' + i,
|
||||
mockLimitCapability =
|
||||
jasmine.createSpyObj('limit-' + id, ['evaluate']);
|
||||
|
||||
mockObject.getId.andReturn(id);
|
||||
mockObject.getCapability.andCallFake(function (key) {
|
||||
return (key === 'limit') && mockLimitCapability;
|
||||
});
|
||||
|
||||
mockLimitCapability.evaluate
|
||||
.andReturn({ cssClass: 'alarm-' + id });
|
||||
});
|
||||
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
mockHandler.handle.mostRecentCall.args[1]();
|
||||
|
||||
mockTelemetryObjects.forEach(function (mockTelemetryObject) {
|
||||
expect(controller.getLegendClass(mockTelemetryObject))
|
||||
.toEqual('alarm-' + mockTelemetryObject.getId());
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
103
platform/features/plot/test/elements/PlotLimitTrackerSpec.js
Normal file
103
platform/features/plot/test/elements/PlotLimitTrackerSpec.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/*****************************************************************************
|
||||
* 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/elements/PlotLimitTracker"],
|
||||
function (PlotLimitTracker) {
|
||||
"use strict";
|
||||
|
||||
describe("A plot's limit tracker", function () {
|
||||
var mockHandle,
|
||||
testRange,
|
||||
mockTelemetryObjects,
|
||||
testData,
|
||||
mockLimitCapabilities,
|
||||
tracker;
|
||||
|
||||
beforeEach(function () {
|
||||
testRange = "some-range";
|
||||
testData = {};
|
||||
mockHandle = jasmine.createSpyObj(
|
||||
'handle',
|
||||
['getTelemetryObjects', 'getDatum']
|
||||
);
|
||||
mockTelemetryObjects = ['a', 'b', 'c'].map(function (id, i) {
|
||||
var mockTelemetryObject = jasmine.createSpyObj(
|
||||
'object-' + id,
|
||||
[ 'getId', 'getCapability', 'getModel' ]
|
||||
),
|
||||
mockLimitCapability = jasmine.createSpyObj(
|
||||
'limit-' + id,
|
||||
[ 'evaluate' ]
|
||||
);
|
||||
testData[id] = { id: id, value: i };
|
||||
mockTelemetryObject.getId.andReturn(id);
|
||||
mockTelemetryObject.getCapability.andCallFake(function (key) {
|
||||
return key === 'limit' && mockLimitCapability;
|
||||
});
|
||||
mockLimitCapability.evaluate
|
||||
.andReturn({ cssClass: 'alarm-' + id});
|
||||
return mockTelemetryObject;
|
||||
});
|
||||
mockHandle.getTelemetryObjects.andReturn(mockTelemetryObjects);
|
||||
mockHandle.getDatum.andCallFake(function (telemetryObject) {
|
||||
return testData[telemetryObject.getId()];
|
||||
});
|
||||
|
||||
tracker = new PlotLimitTracker(mockHandle, testRange);
|
||||
});
|
||||
|
||||
it("initially provides no limit state", function () {
|
||||
mockTelemetryObjects.forEach(function (mockTelemetryObject) {
|
||||
expect(tracker.getLegendClass(mockTelemetryObject))
|
||||
.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when asked to update", function () {
|
||||
beforeEach(function () {
|
||||
tracker.update();
|
||||
});
|
||||
|
||||
it("evaluates limits using the limit capability", function () {
|
||||
mockTelemetryObjects.forEach(function (mockTelemetryObject) {
|
||||
var id = mockTelemetryObject.getId(),
|
||||
mockLimit =
|
||||
mockTelemetryObject.getCapability('limit');
|
||||
expect(mockLimit.evaluate)
|
||||
.toHaveBeenCalledWith(testData[id], testRange);
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes legend classes returned by the limit capability", function () {
|
||||
mockTelemetryObjects.forEach(function (mockTelemetryObject) {
|
||||
var id = mockTelemetryObject.getId();
|
||||
expect(tracker.getLegendClass(mockTelemetryObject))
|
||||
.toEqual('alarm-' + id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -6,6 +6,7 @@
|
||||
"SubPlot",
|
||||
"SubPlotFactory",
|
||||
"elements/PlotAxis",
|
||||
"elements/PlotLimitTracker",
|
||||
"elements/PlotLine",
|
||||
"elements/PlotLineBuffer",
|
||||
"elements/PlotPalette",
|
||||
|
||||
@@ -32,16 +32,14 @@ define(
|
||||
var TEST_RANGE_VALUE = "some formatted range value";
|
||||
|
||||
describe("A range column", function () {
|
||||
var mockDataSet,
|
||||
var testDatum,
|
||||
testMetadata,
|
||||
mockFormatter,
|
||||
mockDomainObject,
|
||||
column;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDataSet = jasmine.createSpyObj(
|
||||
"data",
|
||||
[ "getRangeValue" ]
|
||||
);
|
||||
testDatum = { testKey: 123, otherKey: 456 };
|
||||
mockFormatter = jasmine.createSpyObj(
|
||||
"formatter",
|
||||
[ "formatDomainValue", "formatRangeValue" ]
|
||||
@@ -50,6 +48,10 @@ define(
|
||||
key: "testKey",
|
||||
name: "Test Name"
|
||||
};
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[ "getModel", "getCapability" ]
|
||||
);
|
||||
mockFormatter.formatRangeValue.andReturn(TEST_RANGE_VALUE);
|
||||
|
||||
column = new RangeColumn(testMetadata, mockFormatter);
|
||||
@@ -59,20 +61,13 @@ define(
|
||||
expect(column.getTitle()).toEqual("Test Name");
|
||||
});
|
||||
|
||||
xit("looks up data from a data set", function () {
|
||||
column.getValue(undefined, mockDataSet, 42);
|
||||
expect(mockDataSet.getRangeValue)
|
||||
.toHaveBeenCalledWith(42, "testKey");
|
||||
});
|
||||
|
||||
xit("formats range values as numbers", function () {
|
||||
mockDataSet.getRangeValue.andReturn(123.45678);
|
||||
expect(column.getValue(undefined, mockDataSet, 42).text)
|
||||
it("formats range values as numbers", function () {
|
||||
expect(column.getValue(mockDomainObject, testDatum).text)
|
||||
.toEqual(TEST_RANGE_VALUE);
|
||||
|
||||
// Make sure that service interactions were as expected
|
||||
expect(mockFormatter.formatRangeValue)
|
||||
.toHaveBeenCalledWith(123.45678);
|
||||
.toHaveBeenCalledWith(testDatum.testKey);
|
||||
expect(mockFormatter.formatDomainValue)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ define(
|
||||
* @param {platform/representation.TemplateLinker} templateLinker
|
||||
* the `templateLinker` service, used to load and cache
|
||||
* template extensions
|
||||
* @param {...{templateUrl: string}[]} extensions arrays
|
||||
* @param {...Array.<{templateUrl: string}>} extensions arrays
|
||||
* of template or template-like extensions
|
||||
*/
|
||||
function TemplatePrefetcher(templateLinker, extensions) {
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<div class="search-result-item"
|
||||
<div class="search-result-item l-flex-row flex-elem grows"
|
||||
ng-class="{selected: ngModel.selectedObject.getId() === domainObject.getId()}">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="domainObject"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = domainObject">
|
||||
ng-click="ngModel.selectedObject = domainObject"
|
||||
class="l-flex-row flex-elem grows">
|
||||
</mct-representation>
|
||||
</div>
|
||||
@@ -20,11 +20,13 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="l-flex-col flex-elem grows holder holder-search" ng-controller="SearchController as controller">
|
||||
<div class="search-bar flex-elem" ng-controller="ClickAwayController as toggle">
|
||||
<div class="search-bar flex-elem"
|
||||
ng-controller="ClickAwayController as toggle"
|
||||
ng-class="{ holder: !(ngModel.input === '' || ngModel.input === undefined) }">
|
||||
<input class="search-input"
|
||||
type="text"
|
||||
ng-model="ngModel.input"
|
||||
ng-keyup="controller.search()" />
|
||||
ng-keyup="controller.search()"/>
|
||||
<a class="clear-icon"
|
||||
ng-class="{show: !(ngModel.input === '' || ngModel.input === undefined)}"
|
||||
ng-click="ngModel.input = ''; controller.search()"></a>
|
||||
@@ -37,18 +39,19 @@
|
||||
ng-click="toggle.setState(true)">
|
||||
</mct-include>
|
||||
</div>
|
||||
<div class="active-filter-display flex-elem"
|
||||
<div class="active-filter-display flex-elem holder"
|
||||
ng-class="{off: ngModel.filtersString === '' || ngModel.filtersString === undefined || !ngModel.search}"
|
||||
ng-controller="SearchMenuController as menuController">
|
||||
<a class="clear-icon clear-filters-icon"
|
||||
ng-click="ngModel.checkAll = true; menuController.checkAll()"></a>Filtered by: {{ ngModel.filtersString }}
|
||||
</div>
|
||||
<div class="search-results flex-elem grows vscroll"
|
||||
<div class="search-results flex-elem holder grows vscroll"
|
||||
ng-class="{ off: !(loading || results.length > 0), loading: loading }">
|
||||
<mct-representation key="'search-item'"
|
||||
ng-repeat="result in results"
|
||||
mct-object="result.object"
|
||||
ng-model="ngModel">
|
||||
ng-model="ngModel"
|
||||
class="l-flex-row flex-elem grows">
|
||||
</mct-representation>
|
||||
<a class="load-more-button s-btn vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</a>
|
||||
</div>
|
||||
|
||||
@@ -47,7 +47,13 @@ define(
|
||||
mockQ = jasmine.createSpyObj('$q', ['when', 'all']);
|
||||
mockSubscription = jasmine.createSpyObj(
|
||||
'subscription',
|
||||
['unsubscribe', 'getTelemetryObjects', 'promiseTelemetryObjects']
|
||||
[
|
||||
'makeDatum',
|
||||
'getDatum',
|
||||
'unsubscribe',
|
||||
'getTelemetryObjects',
|
||||
'promiseTelemetryObjects'
|
||||
]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
@@ -112,6 +118,20 @@ define(
|
||||
expect(handle.getSeries(mockDomainObject))
|
||||
.toEqual(mockSeries);
|
||||
});
|
||||
|
||||
it("provides access to the datum objects by index", function () {
|
||||
var testDatum = { a: 1, b: 2 }, testIndex = 42;
|
||||
mockSubscription.makeDatum.andReturn(testDatum);
|
||||
handle.request({});
|
||||
expect(handle.getDatum(mockDomainObject, testIndex))
|
||||
.toEqual(testDatum);
|
||||
expect(mockSubscription.makeDatum)
|
||||
.toHaveBeenCalledWith(
|
||||
mockDomainObject,
|
||||
mockSeries,
|
||||
testIndex
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -243,6 +243,26 @@ define(
|
||||
subscription.unsubscribe();
|
||||
expect(mockUnlisten).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("provides telemetry as datum objects", function () {
|
||||
var testDatum = { a: 1, b: 13, c: 42, d: -1977 };
|
||||
|
||||
function lookup(index, key) {
|
||||
return testDatum[key];
|
||||
}
|
||||
|
||||
mockSeries.getDomainValue.andCallFake(lookup);
|
||||
mockSeries.getRangeValue.andCallFake(lookup);
|
||||
|
||||
testMetadata.domains = [ { key: 'a' }, { key: 'b'} ];
|
||||
testMetadata.ranges = [ { key: 'c' }, { key: 'd'} ];
|
||||
|
||||
mockTelemetry.subscribe.mostRecentCall.args[0](mockSeries);
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
|
||||
expect(subscription.getDatum(mockDomainObject))
|
||||
.toEqual(testDatum);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user