Merge remote-tracking branch 'github/master' into open116

Merge in latest from master into topic branch for
https://github.com/nasa/openmctweb/issues/116

Conflicts:
	platform/features/layout/test/FixedControllerSpec.js
	platform/features/plot/test/PlotControllerSpec.js
This commit is contained in:
Victor Woeltjen 2015-12-30 10:15:05 -08:00
commit a49deb5ab1
41 changed files with 1779 additions and 774 deletions

View File

@ -106,7 +106,7 @@ GLOBAL.window = GLOBAL.window || GLOBAL; // nomnoml expects window to be define
} }
// Convert from Github-flavored Markdown to HTML // Convert from Github-flavored Markdown to HTML
function gfmifier() { function gfmifier(renderTOC) {
var transform = new stream.Transform({ objectMode: true }), var transform = new stream.Transform({ objectMode: true }),
markdown = ""; markdown = "";
transform._transform = function (chunk, encoding, done) { transform._transform = function (chunk, encoding, done) {
@ -114,9 +114,11 @@ GLOBAL.window = GLOBAL.window || GLOBAL; // nomnoml expects window to be define
done(); done();
}; };
transform._flush = function (done) { transform._flush = function (done) {
// Prepend table of contents if (renderTOC){
markdown = // Prepend table of contents
[ TOC_HEAD, toc(markdown).content, "", markdown ].join("\n"); markdown =
[ TOC_HEAD, toc(markdown).content, "", markdown ].join("\n");
}
this.push(header); this.push(header);
this.push(marked(markdown)); this.push(marked(markdown));
this.push(footer); this.push(footer);
@ -168,13 +170,16 @@ GLOBAL.window = GLOBAL.window || GLOBAL; // nomnoml expects window to be define
var destination = file.replace(options['in'], options.out) var destination = file.replace(options['in'], options.out)
.replace(/md$/, "html"), .replace(/md$/, "html"),
destPath = path.dirname(destination), destPath = path.dirname(destination),
prefix = path.basename(destination).replace(/\.html$/, ""); prefix = path.basename(destination).replace(/\.html$/, ""),
//Determine whether TOC should be rendered for this file based
//on regex provided as command line option
renderTOC = file.match(options['suppress-toc'] || "") === null;
mkdirp(destPath, function (err) { mkdirp(destPath, function (err) {
fs.createReadStream(file, { encoding: 'utf8' }) fs.createReadStream(file, { encoding: 'utf8' })
.pipe(split()) .pipe(split())
.pipe(nomnomlifier(destPath, prefix)) .pipe(nomnomlifier(destPath, prefix))
.pipe(gfmifier()) .pipe(gfmifier(renderTOC))
.pipe(fs.createWriteStream(destination, { .pipe(fs.createWriteStream(destination, {
encoding: 'utf8' encoding: 'utf8'
})); }));

View File

@ -1,38 +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.
-->
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Open MCT Web Documentation</title>
</head>
<body class="user-environ" ng-view>
Sections:
<ul>
<li><a href="api/">API</a></li>
<li><a href="architecture/">Architecture Overview</a></li>
<li><a href="guide/">Developer Guide</a></li>
<li><a href="tutorials/">Tutorials</a></li>
<li><a href="process/">Development Process</a></li>
</ul>
</body>
</html>

35
docs/src/index.md Normal file
View File

@ -0,0 +1,35 @@
# Open MCT Web Documentation
## Overview
Documentation is provided to support the use and development of
Open MCT Web. It's recommended that before doing
any development with Open MCT Web you take some time to familiarize yourself
with the documentation below.
Open MCT Web provides functionality out of the box, but it's also a platform for
building rich mission operations applications based on modern web technology.
The platform is configured declaratively, and defines conventions for
building on the provided capabilities by creating modular 'bundles' that
extend the platform at a variety of extension points. The details of how to
extend the platform are provided in the following documentation.
## Sections
* The [Architecture Overview](architecture/) describes the concepts used
throughout Open MCT Web, and gives a high level overview of the platform's design.
* The [Developer's Guide](guide/) goes into more detail about how to use the
platform and the functionality that it provides.
* The [Tutorials](tutorials/) give examples of extending the platform to add
functionality,
and integrate with data sources.
* The [API](api/) document is generated from inline documentation
using [JSDoc](http://usejsdoc.org/), and describes the JavaScript objects and
functions that make up the software platform.
* Finally, the [Development Process](process/) document describes the
Open MCT Web software development cycle.

View File

@ -31,7 +31,7 @@
"jshint": "jshint platform example || exit 0", "jshint": "jshint platform example || exit 0",
"watch": "karma start", "watch": "karma start",
"jsdoc": "jsdoc -c jsdoc.json -r -d target/docs/api", "jsdoc": "jsdoc -c jsdoc.json -r -d target/docs/api",
"otherdoc": "node docs/gendocs.js --in docs/src --out target/docs", "otherdoc": "node docs/gendocs.js --in docs/src --out target/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
"docs": "npm run jsdoc ; npm run otherdoc" "docs": "npm run jsdoc ; npm run otherdoc"
}, },
"repository": { "repository": {

View File

@ -24,7 +24,9 @@
<ul class="tree"> <ul class="tree">
<li ng-repeat="containedObject in composition"> <li ng-repeat="containedObject in composition">
<span class="tree-item"> <span class="tree-item">
<mct-representation key="'label'" mct-object="containedObject"> <mct-representation key="'label'"
mct-object="containedObject"
class="rep-object-label">
</mct-representation> </mct-representation>
</span> </span>
</li> </li>

View File

@ -71,7 +71,7 @@ $itemPadLR: 5px;
$treeVCW: 10px; $treeVCW: 10px;
$treeTypeIconH: 1.4em; // was 16px $treeTypeIconH: 1.4em; // was 16px
$treeTypeIconHPx: 16px; $treeTypeIconHPx: 16px;
$treeTypeIconW: 20px; $treeTypeIconW: 18px;
$treeContextTriggerW: 20px; $treeContextTriggerW: 20px;
// Tabular // Tabular
$tabularHeaderH: 22px; //18px $tabularHeaderH: 22px; //18px

View File

@ -73,31 +73,34 @@
} }
.l-icon-alert { .l-icon-alert {
display: none !important; // Remove this when alerts are enabled display: none !important;
&:before { &:before {
color: $colorAlert; color: $colorAlert;
content: "!"; content: "!";
} }
} }
// NEW!!
.t-item-icon { .t-item-icon {
// Used in grid-item.html, tree-item, inspector location, more? // Used in grid-item.html, tree-item, inspector location, more?
@extend .ui-symbol; @extend .ui-symbol;
@extend .icon; @extend .icon;
display: inline-block;
line-height: normal; // This is Ok for the symbolsfont line-height: normal; // This is Ok for the symbolsfont
position: relative; position: relative;
.t-item-icon-glyph {
position: absolute;
}
&.l-icon-link { &.l-icon-link {
&:before { .t-item-icon-glyph {
color: $colorIconLink; &:before {
content: "\f4"; color: $colorIconLink;
height: auto; width: auto; content: "\f4";
position: absolute; height: auto; width: auto;
left: 0; top: 0; right: 0; bottom: 10%; position: absolute;
@include transform-origin(bottom, left); left: 0; top: 0; right: 0; bottom: 10%;
@include transform(scale(0.3)); @include transform-origin(bottom, left);
z-index: 2; @include transform(scale(0.3));
z-index: 2;
}
} }
} }
} }

View File

@ -84,12 +84,20 @@
} }
.inspector-location { .inspector-location {
//line-height: 180%;
.location-item { .location-item {
$h: 1.2em;
@include box-sizing(border-box);
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
line-height: $h;
position: relative; position: relative;
padding: 2px 4px; padding: 2px 4px;
.t-object-label {
.t-item-icon {
height: $h;
width: 0.7rem;
}
}
&:hover { &:hover {
background: $colorItemTreeHoverBg; background: $colorItemTreeHoverBg;
color: $colorItemTreeHoverFg; color: $colorItemTreeHoverFg;
@ -104,6 +112,7 @@
display: inline-block; display: inline-block;
font-family: symbolsfont; font-family: symbolsfont;
font-size: 8px; font-size: 8px;
font-style: normal !important;
line-height: inherit; line-height: inherit;
margin-left: $interiorMarginSm; margin-left: $interiorMarginSm;
width: 4px; width: 4px;

View File

@ -60,6 +60,7 @@
@import "overlay/overlay"; @import "overlay/overlay";
@import "mobile/overlay/overlay"; @import "mobile/overlay/overlay";
@import "tree/tree"; @import "tree/tree";
@import "object-label";
@import "mobile/tree"; @import "mobile/tree";
@import "user-environ/frame"; @import "user-environ/frame";
@import "user-environ/top-bar"; @import "user-environ/top-bar";

View File

@ -300,7 +300,7 @@
@include desktop { @include desktop {
@if $bgHov != none { @if $bgHov != none {
&:not(.disabled):hover { &:not(.disabled):hover {
background: $bgHov; @include background-image($bgHov);
>.icon { >.icon {
color: lighten($ic, $ltGamma); color: lighten($ic, $ltGamma);
} }

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

View File

@ -37,6 +37,8 @@
} }
.status.block { .status.block {
$transDelay: 1.5s;
$transSpeed: .25s;
color: $colorStatusDefault; color: $colorStatusDefault;
cursor: default; cursor: default;
display: inline-block; display: inline-block;
@ -44,13 +46,47 @@
.status-indicator, .status-indicator,
.label, .label,
.count { .count {
//@include test(#00ff00);
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
} }
&.no-icon {
.status-indicator {
display: none;
}
}
&.float-right {
float: right;
}
&.subtle {
opacity: 0.5;
}
.status-indicator { .status-indicator {
margin-right: $interiorMarginSm; 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, &.ok .status-indicator,
&.info .status-indicator { &.info .status-indicator {
color: $colorStatusInfo; color: $colorStatusInfo;
@ -63,26 +99,11 @@
&.error .status-indicator { &.error .status-indicator {
color: $colorStatusError; color: $colorStatusError;
} }
.label {
// Max-width silliness is necessary for width transition
@include trans-prop-nice(max-width, .25s);
overflow: hidden;
max-width: 0px;
}
.count { .count {
@include trans-prop-nice(opacity, .25s); @include trans-prop-nice(opacity, $transSpeed, $transDelay);
font-weight: bold; font-weight: bold;
opacity: 1; opacity: 1;
} }
&:hover {
.label {
max-width: 450px;
width: auto;
}
.count {
opacity: 0;
}
}
} }
/* Styles for messages and message banners */ /* Styles for messages and message banners */

View File

@ -24,21 +24,27 @@
100% { transform: rotate(359deg); } 100% { transform: rotate(359deg); }
} }
@mixin wait-spinner2($b: 5px, $c: $colorAlt1) { @mixin spinner($b: 5px) {
@include keyframes(rotateCentered) { @include keyframes(rotateCentered) {
0% { transform: translateX(-50%) translateY(-50%) rotate(0deg); } 0% { @include transform(translateX(-50%) translateY(-50%) rotate(0deg)); }
100% { transform: translateX(-50%) translateY(-50%) rotate(359deg); } 100% { @include transform(translateX(-50%) translateY(-50%) rotate(359deg)); }
} }
@include animation-name(rotateCentered); @include animation-name(rotateCentered);
@include animation-duration(0.5s); @include animation-duration(0.5s);
@include animation-iteration-count(infinite); @include animation-iteration-count(infinite);
@include animation-timing-function(linear); @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-color: rgba($c, 0.25);
border-top-color: rgba($c, 1.0); border-top-color: rgba($c, 1.0);
border-style: solid;
border-width: 5px;
@include border-radius(100%);
@include box-sizing(border-box);
display: block; display: block;
position: absolute; position: absolute;
height: 0; width: 0; height: 0; width: 0;

View File

@ -31,7 +31,7 @@ $tabletItemH: floor($ueBrowseGridItemLg/3);
/************************** MOBILE TREE MENU DIMENSIONS */ /************************** MOBILE TREE MENU DIMENSIONS */
$mobileTreeItemH: 35px; $mobileTreeItemH: 35px;
$mobileTreeItemIndent: 20px; $mobileTreeItemIndent: 15px;
$mobileTreeRightArrowW: 30px; $mobileTreeRightArrowW: 30px;
/************************** DEVICE WIDTHS */ /************************** DEVICE WIDTHS */

View File

@ -30,25 +30,30 @@
} }
.tree-item, .tree-item,
.search-result-item { .search-result-item {
height: $mobileTreeItemH; height: $mobileTreeItemH !important;
line-height: $mobileTreeItemH; line-height: $mobileTreeItemH !important;
margin-bottom: 0px; margin-bottom: 0px !important;
.view-control { .view-control {
//@include test(red); font-size: 1.2em;
position: absolute; margin-right: 0;
font-size: 1.1em; order: 2;
height: $mobileTreeItemH; width: $mobileTreeItemH;
line-height: inherit; &.has-children {
right: 0px; &:before {
width: $mobileTreeRightArrowW; content: "\7d";
text-align: center; left: 50%;
@include transform(translateX(-50%) rotate(90deg));
}
&.expanded:before {
@include transform(translateX(-50%) rotate(270deg));
}
}
} }
.label,
.t-object-label { .t-object-label {
left: 0;
right: $mobileTreeRightArrowW + $interiorMargin; // Allows tree item name to stop prior to the arrow
line-height: inherit; 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
}
} }
} }
} }

View File

@ -1,5 +1,5 @@
@include phone { @include phone {
.search { .search-holder {
.search-bar { .search-bar {
// Hide menu-icon and adjust spacing when in phone mode // Hide menu-icon and adjust spacing when in phone mode
.menu-icon { .menu-icon {

View File

@ -82,6 +82,7 @@
left: $interiorMarginSm; left: $interiorMarginSm;
@include trans-prop-nice(color, 250ms); @include trans-prop-nice(color, 250ms);
pointer-events: none; pointer-events: none;
z-index: 1;
} }
// Make icon lighten when hovering over search bar // Make icon lighten when hovering over search bar
@ -127,7 +128,7 @@
} }
.active-filter-display { .active-filter-display {
$s: 0.65em; $s: 0.7em;
$p: $interiorMargin; $p: $interiorMargin;
@include box-sizing(border-box); @include box-sizing(border-box);
line-height: 130%; line-height: 130%;
@ -146,7 +147,6 @@
.search-results { .search-results {
@include trans-prop-nice((opacity, visibility), 250ms); @include trans-prop-nice((opacity, visibility), 250ms);
margin-top: $interiorMarginLg; // Always include margin here to fend off the search input
padding-right: $interiorMargin; padding-right: $interiorMargin;
.hint { .hint {
margin-bottom: $interiorMarginLg; margin-bottom: $interiorMarginLg;

View File

@ -35,23 +35,35 @@ ul.tree {
.tree-item, .tree-item,
.search-result-item { .search-result-item {
$runningItemW: 0; $runningItemW: 0;
@extend .l-flex-row;
@include box-sizing(border-box); @include box-sizing(border-box);
@include border-radius($basicCr); @include border-radius($basicCr);
@include single-transition(background-color, 0.25s); @include single-transition(background-color, 0.25s);
display: block;
font-size: 0.8rem; font-size: 0.8rem;
height: $menuLineH; height: $menuLineH;
line-height: $menuLineH; line-height: $menuLineH;
margin-bottom: $interiorMarginSm; margin-bottom: $interiorMarginSm;
padding: 0 $interiorMarginSm;
position: relative; position: relative;
.view-control { .view-control {
color: $colorItemTreeVC; color: $colorItemTreeVC;
display: inline-block; font-size: 0.75em;
margin-left: $interiorMargin; margin-right: $interiorMargin;
font-size: 0.75em; height: 100%;
line-height: inherit;
width: $treeVCW; 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 { @include desktop {
&:hover { &:hover {
color: $colorItemTreeVCHover !important; color: $colorItemTreeVCHover !important;
@ -59,64 +71,17 @@ ul.tree {
} }
} }
.label,
.t-object-label { .t-object-label {
display: block;
@include absPosDefault();
line-height: $menuLineH; line-height: $menuLineH;
.t-item-icon { .t-item-icon {
@include txtShdwSubtle($shdwItemTreeIcon); @include txtShdwSubtle($shdwItemTreeIcon);
font-size: $treeTypeIconH; font-size: $treeTypeIconH;
color: $colorItemTreeIcon; color: $colorItemTreeIcon;
position: absolute; width: $treeTypeIconW;
left: $interiorMargin;
top: 50%;
width: $treeTypeIconH;
@include transform(translateY(-50%));
} }
.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 { .t-title-label {
@include absPosDefault(); @include ellipsize();
display: block; }
left: $runningItemW + ($interiorMargin * 3);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
} }
&.selected { &.selected {
@ -126,12 +91,11 @@ ul.tree {
color: $colorItemTreeSelectedVC; color: $colorItemTreeSelectedVC;
} }
.t-object-label .t-item-icon { .t-object-label .t-item-icon {
color: $colorItemTreeSelectedFg; //$colorItemTreeIconHover; color: $colorItemTreeSelectedFg;
} }
} }
&:not(.selected) { &:not(.selected) {
// NOTE: [Mobile] Removed Hover on Mobile
@include desktop { @include desktop {
&:hover { &:hover {
background: $colorItemTreeHoverBg; background: $colorItemTreeHoverBg;
@ -160,8 +124,28 @@ ul.tree {
} }
} }
.tree-item { mct-representation {
.t-object-label { &.s-status-pending {
left: $interiorMargin + $treeVCW; .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);
} }

View File

@ -20,7 +20,6 @@
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! --> <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<!--<div ng-init="reps = [1,2,3]"></div>-->
<div class='status block' <div class='status block'
title="{{ngModel.getDescription()}}" title="{{ngModel.getDescription()}}"
ng-click='ngModel.configure()' ng-click='ngModel.configure()'

View File

@ -19,7 +19,9 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<span class="t-object-label"> <div class="t-object-label l-flex-row flex-elem grows">
<span class="t-item-icon" ng-class="{ 'l-icon-link':location.isLink() }">{{type.getGlyph()}}</span> <div class="t-item-icon flex-elem" ng-class="{ 'l-icon-link':location.isLink() }">
<span class='t-title-label'>{{model.name}}</span> <div class="t-item-icon-glyph">{{type.getGlyph()}}</div>
</span> </div>
<div class='t-title-label flex-elem grows'>{{model.name}}</div>
</div>

View File

@ -41,7 +41,7 @@
mct-object="parent" mct-object="parent"
ng-model="ngModel" ng-model="ngModel"
ng-click="ngModel.selectedObject = parent" ng-click="ngModel.selectedObject = parent"
class="location-item"> class="location-item rep-object-label">
</mct-representation> </mct-representation>
</span> </span>
</li> </li>
@ -54,7 +54,7 @@
mct-object="parent" mct-object="parent"
ng-model="ngModel" ng-model="ngModel"
ng-click="ngModel.selectedObject = parent" ng-click="ngModel.selectedObject = parent"
class="location-item"> class="location-item rep-object-label">
</mct-representation> </mct-representation>
</span> </span>
</li> </li>

View File

@ -26,41 +26,18 @@
ng-class="{selected: treeNode.isSelected()}" ng-class="{selected: treeNode.isSelected()}"
> >
<span <span
mct-device="desktop" class='ui-symbol view-control flex-elem'
class='ui-symbol view-control' ng-class="{ 'has-children': model.composition !== undefined, expanded: toggle.isActive() }"
ng-click="toggle.toggle(); treeNode.trackExpansion()" ng-click="toggle.toggle(); treeNode.trackExpansion()"
ng-if="model.composition !== undefined"
> >
{{toggle.isActive() ? "v" : ">"}}
</span> </span>
<mct-representation <mct-representation
mct-device="desktop" class="rep-object-label"
class="mobile-hide"
key="'label'" key="'label'"
mct-object="domainObject" mct-object="domainObject"
ng-click="treeNode.select()" ng-click="treeNode.select()"
> >
</mct-representation> </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>
<span <span
class="tree-item-subtree" class="tree-item-subtree"

View File

@ -13,6 +13,12 @@
"implementation": "AgentService.js", "implementation": "AgentService.js",
"depends": [ "$window" ] "depends": [ "$window" ]
} }
],
"runs": [
{
"implementation": "DeviceClassifier.js",
"depends": [ "agentService", "$document" ]
}
] ]
} }
} }

View File

@ -46,6 +46,7 @@ define(
this.userAgent = userAgent; this.userAgent = userAgent;
this.mobileName = matches[0]; this.mobileName = matches[0];
this.$window = $window; this.$window = $window;
this.touchEnabled = ($window.ontouchstart !== undefined);
} }
/** /**
@ -92,6 +93,14 @@ define(
return !this.isPortrait(); 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, * Check if the user agent matches a certain named device,
* as indicated by checking for a case-insensitive substring * as indicated by checking for a case-insensitive substring

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

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

View File

@ -22,31 +22,10 @@
/*global define,Promise*/ /*global define,Promise*/
define( define(
function () { ['./DeviceMatchers'],
function (DeviceMatchers) {
'use strict'; '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, * The `mct-device` directive, when applied as an attribute,
* only includes the element when the device being used matches * only includes the element when the device being used matches
@ -68,6 +47,7 @@ define(
* * `desktop`: Non-mobile devices. * * `desktop`: Non-mobile devices.
* * `portrait`: Devices in a portrait-style orientation. * * `portrait`: Devices in a portrait-style orientation.
* * `landscape`: Devices in a landscape-style orientation. * * `landscape`: Devices in a landscape-style orientation.
* * `touch`: Device supports touch events.
* *
* @param {AgentService} agentService used to detect device type * @param {AgentService} agentService used to detect device type
* based on information about the user agent * based on information about the user agent
@ -77,7 +57,7 @@ define(
function deviceMatches(tokens) { function deviceMatches(tokens) {
tokens = tokens || ""; tokens = tokens || "";
return tokens.split(" ").every(function (token) { return tokens.split(" ").every(function (token) {
var fn = DEVICE_MATCHERS[token]; var fn = DeviceMatchers[token];
return fn && fn(agentService); return fn && fn(agentService);
}); });
} }

View File

@ -82,6 +82,15 @@ define(
expect(agentService.isLandscape()).toBeFalsy(); 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 () { it("allows for checking browser type", function () {
testWindow.navigator.userAgent = "Chromezilla Safarifox"; testWindow.navigator.userAgent = "Chromezilla Safarifox";
agentService = new AgentService(testWindow); agentService = new AgentService(testWindow);

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

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

View File

@ -1,4 +1,6 @@
[ [
"AgentService", "AgentService",
"DeviceClassifier",
"DeviceMatchers",
"MCTDevice" "MCTDevice"
] ]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@ define(
return "C"; return "C";
}, },
getGlyphClass: function () { getGlyphClass: function () {
return ""; return "no-icon no-collapse float-right subtle";
}, },
getText: function () { getText: function () {
return text; return text;

View File

@ -476,6 +476,42 @@ define(
}); });
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");
});
}); });
} }
); );

View File

@ -286,6 +286,7 @@ define(
expect(mockHandle.request.calls.length).toEqual(2); expect(mockHandle.request.calls.length).toEqual(2);
}); });
it("maintains externally-provided domain axis bounds after data is received", function () { it("maintains externally-provided domain axis bounds after data is received", function () {
mockSeries.getPointCount.andReturn(3); mockSeries.getPointCount.andReturn(3);
mockSeries.getRangeValue.andReturn(42); mockSeries.getRangeValue.andReturn(42);
@ -296,7 +297,7 @@ define(
mockScope.$watch.mostRecentCall.args[1](mockDomainObject); mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
fireEvent("telemetry:display:bounds", [ fireEvent("telemetry:display:bounds", [
{}, {},
{ start: 0, end: 10000 } {start: 0, end: 10000}
]); ]);
mockHandle.request.mostRecentCall.args[1]( mockHandle.request.mostRecentCall.args[1](
mockDomainObject, mockDomainObject,
@ -312,6 +313,33 @@ define(
controller.getSubPlots()[0].panZoomStack.getDimensions()[0] controller.getSubPlots()[0].panZoomStack.getDimensions()[0]
).toEqual(10000); ).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());
});
});
}); });
} }
); );

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

View File

@ -6,6 +6,7 @@
"SubPlot", "SubPlot",
"SubPlotFactory", "SubPlotFactory",
"elements/PlotAxis", "elements/PlotAxis",
"elements/PlotLimitTracker",
"elements/PlotLine", "elements/PlotLine",
"elements/PlotLineBuffer", "elements/PlotLineBuffer",
"elements/PlotPalette", "elements/PlotPalette",

View File

@ -20,11 +20,12 @@
at runtime from the About dialog for additional information. 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()}"> ng-class="{selected: ngModel.selectedObject.getId() === domainObject.getId()}">
<mct-representation key="'label'" <mct-representation key="'label'"
mct-object="domainObject" mct-object="domainObject"
ng-model="ngModel" ng-model="ngModel"
ng-click="ngModel.selectedObject = domainObject"> ng-click="ngModel.selectedObject = domainObject"
class="l-flex-row flex-elem grows">
</mct-representation> </mct-representation>
</div> </div>

View File

@ -20,11 +20,13 @@
at runtime from the About dialog for additional information. 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="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" <input class="search-input"
type="text" type="text"
ng-model="ngModel.input" ng-model="ngModel.input"
ng-keyup="controller.search()" /> ng-keyup="controller.search()"/>
<a class="clear-icon" <a class="clear-icon"
ng-class="{show: !(ngModel.input === '' || ngModel.input === undefined)}" ng-class="{show: !(ngModel.input === '' || ngModel.input === undefined)}"
ng-click="ngModel.input = ''; controller.search()"></a> ng-click="ngModel.input = ''; controller.search()"></a>
@ -37,18 +39,19 @@
ng-click="toggle.setState(true)"> ng-click="toggle.setState(true)">
</mct-include> </mct-include>
</div> </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-class="{off: ngModel.filtersString === '' || ngModel.filtersString === undefined || !ngModel.search}"
ng-controller="SearchMenuController as menuController"> ng-controller="SearchMenuController as menuController">
<a class="clear-icon clear-filters-icon" <a class="clear-icon clear-filters-icon"
ng-click="ngModel.checkAll = true; menuController.checkAll()"></a>Filtered by: {{ ngModel.filtersString }} ng-click="ngModel.checkAll = true; menuController.checkAll()"></a>Filtered by: {{ ngModel.filtersString }}
</div> </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 }"> ng-class="{ off: !(loading || results.length > 0), loading: loading }">
<mct-representation key="'search-item'" <mct-representation key="'search-item'"
ng-repeat="result in results" ng-repeat="result in results"
mct-object="result.object" mct-object="result.object"
ng-model="ngModel"> ng-model="ngModel"
class="l-flex-row flex-elem grows">
</mct-representation> </mct-representation>
<a class="load-more-button s-btn vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</a> <a class="load-more-button s-btn vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</a>
</div> </div>

View File

@ -243,6 +243,26 @@ define(
subscription.unsubscribe(); subscription.unsubscribe();
expect(mockUnlisten).toHaveBeenCalled(); 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);
});
}); });
} }
); );