Merged from master
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"configuration": {
|
||||
"paths": {
|
||||
"uuid": "uuid"
|
||||
}
|
||||
},
|
||||
"extensions": {
|
||||
"routes": [
|
||||
{
|
||||
|
||||
@@ -42,9 +42,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='object-holder abs vscroll'>
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs object-holder">
|
||||
</mct-representation>
|
||||
</span>
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
<mct-split-pane class='contents abs' anchor='left'>
|
||||
<div class='split-pane-component treeview pane left'>
|
||||
<div class="holder abs l-mobile">
|
||||
<mct-representation key="'create-button'" mct-object="navigatedObject">
|
||||
<mct-representation key="'create-button'"
|
||||
mct-object="navigatedObject"
|
||||
mct-device="desktop">
|
||||
</mct-representation>
|
||||
<div class='holder search-holder abs'
|
||||
ng-class="{active: treeModel.search}">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="menu-element wrapper" ng-controller="ClickAwayController as createController">
|
||||
<div class="s-menu major create-btn" ng-click="createController.toggle()">
|
||||
<div class="s-menu-btn major create-btn" ng-click="createController.toggle()">
|
||||
<span class="ui-symbol icon type-icon">+</span>
|
||||
<span class="title-label">Create</span>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* Module defining CreateService. Created by vwoeltje on 11/10/14.
|
||||
*/
|
||||
define(
|
||||
["../../lib/uuid"],
|
||||
["uuid"],
|
||||
function (uuid) {
|
||||
"use strict";
|
||||
|
||||
|
||||
@@ -30,12 +30,11 @@
|
||||
structure="toolbar.structure"
|
||||
ng-model="toolbar.state">
|
||||
</mct-toolbar>
|
||||
<div class='holder abs object-holder work-area'>
|
||||
<mct-representation key="representation.selected.key"
|
||||
toolbar="toolbar"
|
||||
mct-object="representation.selected.key && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<mct-representation key="representation.selected.key"
|
||||
toolbar="toolbar"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="holder abs object-holder work-area">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<mct-splitter></mct-splitter>
|
||||
<div
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
"key": "urlService",
|
||||
"implementation": "services/UrlService.js",
|
||||
"depends": [ "$location" ]
|
||||
},
|
||||
{
|
||||
"key": "popupService",
|
||||
"implementation": "services/PopupService.js",
|
||||
"depends": [ "$document", "$window" ]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
@@ -53,6 +58,16 @@
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "TimeRangeController",
|
||||
"implementation": "controllers/TimeRangeController.js",
|
||||
"depends": [ "$scope", "now" ]
|
||||
},
|
||||
{
|
||||
"key": "DateTimePickerController",
|
||||
"implementation": "controllers/DateTimePickerController.js",
|
||||
"depends": [ "$scope", "now" ]
|
||||
},
|
||||
{
|
||||
"key": "TreeNodeController",
|
||||
"implementation": "controllers/TreeNodeController.js",
|
||||
@@ -118,11 +133,21 @@
|
||||
"implementation": "directives/MCTDrag.js",
|
||||
"depends": [ "$document" ]
|
||||
},
|
||||
{
|
||||
"key": "mctClickElsewhere",
|
||||
"implementation": "directives/MCTClickElsewhere.js",
|
||||
"depends": [ "$document" ]
|
||||
},
|
||||
{
|
||||
"key": "mctResize",
|
||||
"implementation": "directives/MCTResize.js",
|
||||
"depends": [ "$timeout" ]
|
||||
},
|
||||
{
|
||||
"key": "mctPopup",
|
||||
"implementation": "directives/MCTPopup.js",
|
||||
"depends": [ "$compile", "popupService" ]
|
||||
},
|
||||
{
|
||||
"key": "mctScrollX",
|
||||
"implementation": "directives/MCTScroll.js",
|
||||
@@ -226,6 +251,10 @@
|
||||
{
|
||||
"key": "selector",
|
||||
"templateUrl": "templates/controls/selector.html"
|
||||
},
|
||||
{
|
||||
"key": "datetime-picker",
|
||||
"templateUrl": "templates/controls/datetime-picker.html"
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
|
||||
@@ -45,6 +45,7 @@ $ueEditToolBarH: 25px;
|
||||
$ueBrowseLeftPaneW: 25%;
|
||||
$ueEditLeftPaneW: 75%;
|
||||
$treeSearchInputBarH: 25px;
|
||||
$ueTimeControlH: (33px, 20px, 20px);
|
||||
// Overlay
|
||||
$ovrTopBarH: 45px;
|
||||
$ovrFooterH: 24px;
|
||||
@@ -105,3 +106,8 @@ $dirImgs: $dirCommonRes + 'images/';
|
||||
|
||||
/************************** TIMINGS */
|
||||
$controlFadeMs: 100ms;
|
||||
|
||||
/************************** LIMITS */
|
||||
$glyphLimit: '\e603';
|
||||
$glyphLimitUpr: '\0000eb';
|
||||
$glyphLimitLwr: '\0000ee';
|
||||
|
||||
@@ -40,11 +40,11 @@
|
||||
|
||||
/************************** HTML ENTITIES */
|
||||
a {
|
||||
color: #ccc;
|
||||
color: $colorA;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
color: $colorAHov;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,14 @@ mct-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrolling {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.vscroll {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
}
|
||||
|
||||
.ui-symbol {
|
||||
&.type-icon {
|
||||
color: $colorObjHdrIc;
|
||||
}
|
||||
&.icon {
|
||||
color: $colorKey;
|
||||
&.alert {
|
||||
@@ -41,6 +44,9 @@
|
||||
font-size: 1.65em;
|
||||
}
|
||||
}
|
||||
&.icon-calendar:after {
|
||||
content: "\e605";
|
||||
}
|
||||
}
|
||||
|
||||
.bar .ui-symbol {
|
||||
@@ -52,7 +58,7 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.s-menu .invoke-menu,
|
||||
.s-menu-btn .invoke-menu,
|
||||
.icon.major .invoke-menu {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,39 @@
|
||||
@mixin limit($bg, $ic, $glyph) {
|
||||
background: $bg !important;
|
||||
//color: $fg !important;
|
||||
&:before {
|
||||
//@include pulse(1000ms);
|
||||
color: $ic;
|
||||
content: $glyph;
|
||||
}
|
||||
@mixin limitGlyph($iconColor, $glyph: $glyphLimit) {
|
||||
&:before {
|
||||
color: $iconColor;
|
||||
content: $glyph;
|
||||
font-family: symbolsfont;
|
||||
font-size: 0.8em;
|
||||
display: inline;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[class*="s-limit"] {
|
||||
//white-space: nowrap;
|
||||
&:before {
|
||||
display: inline-block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 0.75em;
|
||||
font-style: normal !important;
|
||||
margin-right: $interiorMarginSm;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.s-limit-red { background: $colorLimitRedBg !important; }
|
||||
.s-limit-yellow { background: $colorLimitYellowBg !important; }
|
||||
|
||||
// Handle limit when applied to a tr
|
||||
tr[class*="s-limit"] {
|
||||
&.s-limit-red td:first-child {
|
||||
@include limitGlyph($colorLimitRedIc);
|
||||
}
|
||||
&.s-limit-yellow td:first-child {
|
||||
@include limitGlyph($colorLimitYellowIc);
|
||||
}
|
||||
&.s-limit-upr td:first-child:before { content:$glyphLimitUpr; }
|
||||
&.s-limit-lwr td:first-child:before { content:$glyphLimitLwr; }
|
||||
}
|
||||
|
||||
.s-limit-upr-red { @include limit($colorLimitRedBg, $colorLimitRedIc, "\0000eb"); };
|
||||
.s-limit-upr-yellow { @include limit($colorLimitYellowBg, $colorLimitYellowIc, "\0000ed"); };
|
||||
.s-limit-lwr-yellow { @include limit($colorLimitYellowBg, $colorLimitYellowIc, "\0000ec"); };
|
||||
.s-limit-lwr-red { @include limit($colorLimitRedBg, $colorLimitRedIc, "\0000ee"); };
|
||||
// Handle limit when applied directly to a non-tr element
|
||||
// Assume this is applied to the element that displays the limit value
|
||||
:not(tr)[class*="s-limit"] {
|
||||
&.s-limit-red {
|
||||
@include limitGlyph($colorLimitRedIc);
|
||||
}
|
||||
&.s-limit-yellow {
|
||||
@include limitGlyph($colorLimitYellowIc);
|
||||
}
|
||||
&.s-limit-upr:before { content:$glyphLimitUpr; }
|
||||
&.s-limit-lwr:before { content:$glyphLimitLwr; }
|
||||
}
|
||||
@@ -364,9 +364,10 @@
|
||||
/* This doesn't work on an element inside an element with absolute positioning that has height: auto */
|
||||
//position: relative;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
@include webkitProp(transform, translateY(-50%));
|
||||
//-webkit-transform: translateY(-50%);
|
||||
//-ms-transform: translateY(-50%);
|
||||
//transform: translateY(-50%);
|
||||
}
|
||||
|
||||
@mixin verticalCenterBlock($holderH, $itemH) {
|
||||
@@ -391,22 +392,8 @@
|
||||
overflow-y: $showBar;
|
||||
}
|
||||
|
||||
@mixin wait-spinner($b: 5px, $c: $colorAlt1) {
|
||||
display: block;
|
||||
position: absolute;
|
||||
-webkit-animation: rotation .6s infinite linear;
|
||||
-moz-animation: rotation .6s infinite linear;
|
||||
-o-animation: rotation .6s infinite linear;
|
||||
animation: rotation .6s infinite linear;
|
||||
border-color: rgba($c, 0.25);
|
||||
border-top-color: rgba($c, 1.0);
|
||||
border-style: solid;
|
||||
border-width: $b;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
@mixin test($c: #ffcc00, $a: 0.2) {
|
||||
background-color: rgba($c, $a);
|
||||
background-color: rgba($c, $a) !important;
|
||||
}
|
||||
|
||||
@mixin tmpBorder($c: #ffcc00, $a: 0.75) {
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
&.fixed {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
&.scrolling {
|
||||
overflow: auto;
|
||||
}
|
||||
.controls,
|
||||
label,
|
||||
.inline-block {
|
||||
|
||||
@@ -177,7 +177,7 @@ label.checkbox.custom {
|
||||
}
|
||||
}
|
||||
|
||||
.s-menu label.checkbox.custom {
|
||||
.s-menu-btn label.checkbox.custom {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@@ -349,49 +349,155 @@ label.checkbox.custom {
|
||||
|
||||
.slider {
|
||||
$knobH: 100%; //14px;
|
||||
$knobW: 12px;
|
||||
$slotH: 50%;
|
||||
.slot {
|
||||
// @include border-radius($basicCr * .75);
|
||||
@include sliderTrack();
|
||||
height: $slotH;
|
||||
//@include sliderTrack();
|
||||
width: auto;
|
||||
position: absolute;
|
||||
top: ($knobH - $slotH) / 2;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: auto;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
.knob {
|
||||
@include btnSubtle();
|
||||
@include controlGrippy(rgba(black, 0.3), vertical, 1px, solid);
|
||||
cursor: ew-resize;
|
||||
//@include btnSubtle();
|
||||
//@include controlGrippy(rgba(black, 0.3), vertical, 1px, solid);
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
background-color: $sliderColorKnob;
|
||||
&:hover {
|
||||
background-color: $sliderColorKnobHov;
|
||||
}
|
||||
position: absolute;
|
||||
height: $knobH;
|
||||
width: $knobW;
|
||||
width: $sliderKnobW;
|
||||
top: 0;
|
||||
auto: 0;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
&:before {
|
||||
top: 1px;
|
||||
bottom: 3px;
|
||||
left: ($knobW / 2) - 1;
|
||||
}
|
||||
|
||||
}
|
||||
.knob-l {
|
||||
@include border-left-radius($sliderKnobW);
|
||||
cursor: w-resize;
|
||||
}
|
||||
.knob-r {
|
||||
@include border-right-radius($sliderKnobW);
|
||||
cursor: e-resize;
|
||||
}
|
||||
.range {
|
||||
background: rgba($colorKey, 0.6);
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
background-color: $sliderColorRange;
|
||||
cursor: ew-resize;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: 0; //$tbOffset;
|
||||
right: auto;
|
||||
bottom: 0;
|
||||
left: auto;
|
||||
height: auto;
|
||||
width: auto;
|
||||
&:hover {
|
||||
background: rgba($colorKey, 0.7);
|
||||
background-color: $sliderColorRangeHov;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** DATETIME PICKER */
|
||||
.l-datetime-picker {
|
||||
$r1H: 15px;
|
||||
@include user-select(none);
|
||||
font-size: 0.8rem;
|
||||
padding: $interiorMarginLg !important;
|
||||
width: 230px;
|
||||
.l-month-year-pager {
|
||||
$pagerW: 20px;
|
||||
//@include test();
|
||||
//font-size: 0.8rem;
|
||||
height: $r1H;
|
||||
margin-bottom: $interiorMargin;
|
||||
position: relative;
|
||||
.pager,
|
||||
.val {
|
||||
//@include test(red);
|
||||
@extend .abs;
|
||||
}
|
||||
.pager {
|
||||
width: $pagerW;
|
||||
@extend .ui-symbol;
|
||||
&.prev {
|
||||
right: auto;
|
||||
&:before {
|
||||
content: "\3c";
|
||||
}
|
||||
}
|
||||
&.next {
|
||||
left: auto;
|
||||
text-align: right;
|
||||
&:before {
|
||||
content: "\3e";
|
||||
}
|
||||
}
|
||||
}
|
||||
.val {
|
||||
text-align: center;
|
||||
left: $pagerW + $interiorMargin;
|
||||
right: $pagerW + $interiorMargin;
|
||||
}
|
||||
}
|
||||
.l-calendar,
|
||||
.l-time-selects {
|
||||
border-top: 1px solid $colorInteriorBorder
|
||||
}
|
||||
.l-time-selects {
|
||||
line-height: $formInputH;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** CALENDAR */
|
||||
.l-calendar {
|
||||
$colorMuted: pushBack($colorMenuFg, 30%);
|
||||
ul.l-cal-row {
|
||||
@include display-flex;
|
||||
@include flex-flow(row nowrap);
|
||||
margin-top: 1px;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
li {
|
||||
@include flex(1 0);
|
||||
//@include test();
|
||||
margin-left: 1px;
|
||||
padding: $interiorMargin;
|
||||
text-align: center;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
&.l-header li {
|
||||
color: $colorMuted;
|
||||
}
|
||||
&.l-body li {
|
||||
@include trans-prop-nice(background-color, .25s);
|
||||
cursor: pointer;
|
||||
&.in-month {
|
||||
background-color: $colorCalCellInMonthBg;
|
||||
}
|
||||
.sub {
|
||||
color: $colorMuted;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
&.selected {
|
||||
background: $colorCalCellSelectedBg;
|
||||
color: $colorCalCellSelectedFg;
|
||||
.sub {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background-color: $colorCalCellHovBg;
|
||||
color: $colorCalCellHovFg;
|
||||
.sub {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/******************************************************** MENU BUTTONS */
|
||||
.s-menu {
|
||||
.s-menu-btn {
|
||||
// Formerly .btn-menu
|
||||
@extend .s-btn;
|
||||
span.l-click-area {
|
||||
@@ -62,186 +62,192 @@
|
||||
|
||||
/******************************************************** MENUS THEMSELVES */
|
||||
.menu-element {
|
||||
$bg: $colorMenuBg;
|
||||
$fg: $colorMenuFg;
|
||||
$ic: $colorMenuIc;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
.menu {
|
||||
@include border-radius($basicCr);
|
||||
@include containerSubtle($bg, $fg);
|
||||
@include boxShdw($shdwMenu);
|
||||
@include txtShdw($shdwMenuText);
|
||||
display: block; // set to block via jQuery
|
||||
padding: $interiorMarginSm 0;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
ul {
|
||||
@include menuUlReset();
|
||||
li {
|
||||
@include box-sizing(border-box);
|
||||
border-top: 1px solid lighten($bg, 20%);
|
||||
color: pullForward($bg, 60%);
|
||||
line-height: $menuLineH;
|
||||
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
&:first-child {
|
||||
border: none;
|
||||
}
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
.icon {
|
||||
color: $colorMenuHovIc;
|
||||
}
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu,
|
||||
.context-menu,
|
||||
.super-menu {
|
||||
pointer-events: auto;
|
||||
ul li {
|
||||
//padding-left: 25px;
|
||||
a {
|
||||
color: $fg;
|
||||
}
|
||||
.icon {
|
||||
color: $ic;
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin;
|
||||
}
|
||||
&:hover .icon {
|
||||
//color: lighten($ic, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.s-menu {
|
||||
@include border-radius($basicCr);
|
||||
@include containerSubtle($colorMenuBg, $colorMenuFg);
|
||||
@include boxShdw($shdwMenu);
|
||||
@include txtShdw($shdwMenuText);
|
||||
padding: $interiorMarginSm 0;
|
||||
}
|
||||
|
||||
.checkbox-menu {
|
||||
// Used in search dropdown in tree
|
||||
@extend .context-menu;
|
||||
ul li {
|
||||
padding-left: 50px;
|
||||
.checkbox {
|
||||
$d: 0.7rem;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: ($menuLineH - $d) / 1.5;
|
||||
em {
|
||||
height: $d;
|
||||
width: $d;
|
||||
&:before {
|
||||
font-size: 7px !important;// $d/2;
|
||||
height: $d;
|
||||
width: $d;
|
||||
line-height: $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
.type-icon {
|
||||
left: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.super-menu {
|
||||
$w: 500px;
|
||||
$h: $w - 20;
|
||||
$plw: 50%;
|
||||
$prw: 50%;
|
||||
display: block;
|
||||
width: $w;
|
||||
height: $h;
|
||||
.contents {
|
||||
@include absPosDefault($interiorMargin);
|
||||
}
|
||||
.pane {
|
||||
.menu {
|
||||
@extend .s-menu;
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
ul {
|
||||
@include menuUlReset();
|
||||
li {
|
||||
@include box-sizing(border-box);
|
||||
&.left {
|
||||
//@include test();
|
||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||
left: 0;
|
||||
padding-right: $interiorMargin;
|
||||
right: auto;
|
||||
width: $plw;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
ul {
|
||||
li {
|
||||
@include border-radius($controlCr);
|
||||
padding-left: 30px;
|
||||
border-top: none;
|
||||
}
|
||||
border-top: 1px solid lighten($colorMenuBg, 20%);
|
||||
color: pullForward($colorMenuBg, 60%);
|
||||
line-height: $menuLineH;
|
||||
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
&:first-child {
|
||||
border: none;
|
||||
}
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
.icon {
|
||||
color: $colorMenuHovIc;
|
||||
}
|
||||
}
|
||||
&.right {
|
||||
//@include test(red);
|
||||
left: auto;
|
||||
right: 0;
|
||||
padding: $interiorMargin * 5;
|
||||
width: $prw;
|
||||
.type-icon {
|
||||
left: $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
.menu-item-description {
|
||||
.desc-area {
|
||||
&.icon {
|
||||
$h: 150px;
|
||||
color: $colorCreateMenuLgIcon;
|
||||
position: relative;
|
||||
font-size: 8em;
|
||||
left: 0;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
margin-bottom: $interiorMargin * 5;
|
||||
text-align: center;
|
||||
}
|
||||
&.title {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
&.description {
|
||||
//color: lighten($bg, 30%);
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 0.8em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.context-menu {
|
||||
font-size: 0.80rem;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu-holder {
|
||||
pointer-events: none;
|
||||
.menu,
|
||||
.context-menu,
|
||||
.super-menu {
|
||||
pointer-events: auto;
|
||||
ul li {
|
||||
//padding-left: 25px;
|
||||
a {
|
||||
color: $colorMenuFg;
|
||||
}
|
||||
.icon {
|
||||
color: $colorMenuIc;
|
||||
}
|
||||
.type-icon {
|
||||
left: $interiorMargin;
|
||||
}
|
||||
&:hover .icon {
|
||||
//color: lighten($colorMenuIc, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-menu {
|
||||
// Used in search dropdown in tree
|
||||
@extend .context-menu;
|
||||
ul li {
|
||||
padding-left: 50px;
|
||||
.checkbox {
|
||||
$d: 0.7rem;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: ($menuLineH - $d) / 1.5;
|
||||
em {
|
||||
height: $d;
|
||||
width: $d;
|
||||
&:before {
|
||||
font-size: 7px !important;// $d/2;
|
||||
height: $d;
|
||||
width: $d;
|
||||
line-height: $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
.type-icon {
|
||||
left: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.super-menu {
|
||||
$w: 500px;
|
||||
$h: $w - 20;
|
||||
$plw: 50%;
|
||||
$prw: 50%;
|
||||
display: block;
|
||||
width: $w;
|
||||
height: $h;
|
||||
.contents {
|
||||
@include absPosDefault($interiorMargin);
|
||||
}
|
||||
.pane {
|
||||
@include box-sizing(border-box);
|
||||
&.left {
|
||||
//@include test();
|
||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||
left: 0;
|
||||
padding-right: $interiorMargin;
|
||||
right: auto;
|
||||
width: $plw;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
ul {
|
||||
li {
|
||||
@include border-radius($controlCr);
|
||||
padding-left: 30px;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.right {
|
||||
//@include test(red);
|
||||
left: auto;
|
||||
right: 0;
|
||||
padding: $interiorMargin * 5;
|
||||
width: $prw;
|
||||
}
|
||||
}
|
||||
.menu-item-description {
|
||||
.desc-area {
|
||||
&.icon {
|
||||
$h: 150px;
|
||||
color: $colorCreateMenuLgIcon;
|
||||
position: relative;
|
||||
font-size: 8em;
|
||||
left: 0;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
margin-bottom: $interiorMargin * 5;
|
||||
text-align: center;
|
||||
}
|
||||
&.title {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
&.description {
|
||||
//color: lighten($colorMenuBg, 30%);
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 0.8em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.context-menu {
|
||||
font-size: 0.80rem;
|
||||
}
|
||||
|
||||
.context-menu-holder,
|
||||
.menu-holder {
|
||||
position: absolute;
|
||||
height: 200px;
|
||||
width: 170px;
|
||||
z-index: 70;
|
||||
.context-menu-wrapper {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
.context-menu {
|
||||
}
|
||||
}
|
||||
&.go-left .context-menu {
|
||||
&.go-left .context-menu,
|
||||
&.go-left .menu {
|
||||
right: 0;
|
||||
}
|
||||
&.go-up .context-menu {
|
||||
&.go-up .context-menu,
|
||||
&.go-up .menu {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu-holder {
|
||||
pointer-events: none;
|
||||
height: 200px;
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
.btn-bar.right .menu,
|
||||
.menus-to-left .menu {
|
||||
left: auto;
|
||||
|
||||
@@ -1,72 +1,155 @@
|
||||
.l-time-controller {
|
||||
$inputTxtW: 90px;
|
||||
$knobW: 9px;
|
||||
$r1H: 20px;
|
||||
$r2H: 30px;
|
||||
$r3H: 10px;
|
||||
@mixin toiLineHovEffects() {
|
||||
//@include pulse(.25s);
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: $timeControllerToiLineColorHov;
|
||||
}
|
||||
}
|
||||
|
||||
position: relative;
|
||||
margin: $interiorMarginLg 0;
|
||||
min-width: 400px;
|
||||
.l-time-controller-visible {
|
||||
|
||||
}
|
||||
|
||||
mct-include.l-time-controller {
|
||||
$minW: 500px;
|
||||
$knobHOffset: 0px;
|
||||
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
||||
$rangeValPad: $interiorMargin;
|
||||
$rangeValOffset: $sliderKnobW;
|
||||
//$knobCr: $sliderKnobW;
|
||||
$timeRangeSliderLROffset: 130px + $sliderKnobW + $rangeValOffset;
|
||||
$r1H: nth($ueTimeControlH,1);
|
||||
$r2H: nth($ueTimeControlH,2);
|
||||
$r3H: nth($ueTimeControlH,3);
|
||||
|
||||
@include absPosDefault();
|
||||
//@include test();
|
||||
display: block;
|
||||
top: auto;
|
||||
height: $r1H + $r2H + $r3H + ($interiorMargin * 2);
|
||||
min-width: $minW;
|
||||
font-size: 0.8rem;
|
||||
|
||||
.l-time-range-inputs-holder,
|
||||
.l-time-range-slider {
|
||||
font-size: 0.8em;
|
||||
//font-size: 0.8em;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder,
|
||||
.l-time-range-slider-holder,
|
||||
.l-time-range-ticks-holder
|
||||
{
|
||||
margin-bottom: $interiorMargin;
|
||||
position: relative;
|
||||
//@include test();
|
||||
@include absPosDefault(0, visible);
|
||||
@include box-sizing(border-box);
|
||||
top: auto;
|
||||
}
|
||||
.l-time-range-slider,
|
||||
.l-time-range-ticks {
|
||||
//@include test(red, 0.1);
|
||||
@include absPosDefault(0, visible);
|
||||
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
||||
}
|
||||
|
||||
.l-time-range-inputs-holder {
|
||||
height: $r1H;
|
||||
}
|
||||
|
||||
.l-time-range-slider,
|
||||
.l-time-range-ticks {
|
||||
left: $inputTxtW; right: $inputTxtW;
|
||||
|
||||
//@include test(red);
|
||||
height: $r1H; bottom: $r2H + $r3H + ($interiorMarginSm * 2);
|
||||
padding-top: $interiorMargin;
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
.type-icon {
|
||||
font-size: 120%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.l-time-range-input,
|
||||
.l-time-range-inputs-elem {
|
||||
margin-right: $interiorMargin;
|
||||
.lbl {
|
||||
color: $colorPlotLabelFg;
|
||||
}
|
||||
.ui-symbol.icon {
|
||||
font-size: 11px;
|
||||
width: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-slider-holder {
|
||||
height: $r2H;
|
||||
//@include test(green);
|
||||
height: $r2H; bottom: $r3H + ($interiorMarginSm * 1);
|
||||
.range-holder {
|
||||
@include box-shadow(none);
|
||||
background: none;
|
||||
border: none;
|
||||
height: 75%;
|
||||
.range {
|
||||
.toi-line {
|
||||
$myC: $timeControllerToiLineColor;
|
||||
$myW: 8px;
|
||||
@include transform(translateX(50%));
|
||||
position: absolute;
|
||||
//@include test();
|
||||
top: 0; right: 0; bottom: 0px; left: auto;
|
||||
width: $myW;
|
||||
height: auto;
|
||||
z-index: 2;
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: $myC;
|
||||
content: "";
|
||||
position: absolute;
|
||||
}
|
||||
&:before {
|
||||
// Vert line
|
||||
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
||||
width: 2px;
|
||||
//top: 0; right: 3px; bottom: 0; left: 3px;
|
||||
}
|
||||
&:after {
|
||||
// Circle element
|
||||
@include border-radius($myW);
|
||||
@include transform(translateY(-50%));
|
||||
top: 50%; right: 0; bottom: auto; left: 0;
|
||||
width: auto;
|
||||
height: $myW;
|
||||
}
|
||||
}
|
||||
&:hover .toi-line {
|
||||
@include toiLineHovEffects;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:not(:active) {
|
||||
//@include test(#ff00cc);
|
||||
.knob,
|
||||
.range {
|
||||
@include transition-property(left, right);
|
||||
@include transition-duration(500ms);
|
||||
@include transition-timing-function(ease-in-out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-time-range-ticks-holder {
|
||||
height: $r3H;
|
||||
.l-time-range-ticks {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
border-top: 1px solid $colorTick;
|
||||
.tick {
|
||||
background-color: $colorInteriorBorder;
|
||||
background-color: $colorTick;
|
||||
border:none;
|
||||
height: 5px;
|
||||
width: 1px;
|
||||
margin-left: -1px;
|
||||
position: absolute;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
.l-time-range-tick-label {
|
||||
color: lighten($colorInteriorBorder, 20%);
|
||||
font-size: 0.7em;
|
||||
@include webkitProp(transform, translateX(-50%));
|
||||
color: $colorPlotLabelFg;
|
||||
display: inline-block;
|
||||
font-size: 0.9em;
|
||||
position: absolute;
|
||||
margin-left: -0.5 * $tickLblW;
|
||||
text-align: center;
|
||||
top: $r3H;
|
||||
width: $tickLblW;
|
||||
top: 8px;
|
||||
white-space: nowrap;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
@@ -74,31 +157,47 @@
|
||||
}
|
||||
|
||||
.knob {
|
||||
width: $knobW;
|
||||
z-index: 2;
|
||||
.range-value {
|
||||
$w: 75px;
|
||||
//@include test();
|
||||
//@include test($sliderColorRange);
|
||||
@include trans-prop-nice-fade(.25s);
|
||||
padding: 0 $rangeValOffset;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -7px; // Label is 13px high
|
||||
height: $r2H;
|
||||
line-height: $r2H;
|
||||
white-space: nowrap;
|
||||
width: $w;
|
||||
}
|
||||
&:hover .range-value {
|
||||
color: $colorKey;
|
||||
color: $sliderColorKnobHov;
|
||||
}
|
||||
&.knob-l {
|
||||
margin-left: $knobW / -2;
|
||||
//@include border-bottom-left-radius($knobCr); // MOVED TO _CONTROLS.SCSS
|
||||
margin-left: $knobM;
|
||||
.range-value {
|
||||
text-align: right;
|
||||
right: $knobW + $interiorMargin;
|
||||
right: $rangeValOffset;
|
||||
}
|
||||
}
|
||||
&.knob-r {
|
||||
margin-right: $knobW / -2;
|
||||
//@include border-bottom-right-radius($knobCr);
|
||||
margin-right: $knobM;
|
||||
.range-value {
|
||||
left: $knobW + $interiorMargin;
|
||||
left: $rangeValOffset;
|
||||
}
|
||||
&:hover + .range-holder .range .toi-line {
|
||||
@include toiLineHovEffects;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//.slot.range-holder {
|
||||
// background-color: $sliderColorRangeHolder;
|
||||
//}
|
||||
|
||||
.s-time-range-val {
|
||||
//@include test();
|
||||
@include border-radius($controlCr);
|
||||
background-color: $colorInputBg;
|
||||
padding: 1px 1px 0 $interiorMargin;
|
||||
}
|
||||
@@ -19,39 +19,44 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@mixin complexFieldHolder($myW) {
|
||||
width: $myW + $interiorMargin;
|
||||
input[type="text"] {
|
||||
width: $myW;
|
||||
}
|
||||
}
|
||||
|
||||
.complex.datetime {
|
||||
span {
|
||||
display: inline-block;
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
.field-hints,
|
||||
.fields {
|
||||
}
|
||||
|
||||
|
||||
.field-hints {
|
||||
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
.fields {
|
||||
margin-top: $interiorMarginSm 0;
|
||||
padding: $interiorMarginSm 0;
|
||||
}
|
||||
|
||||
.date {
|
||||
$myW: 80px;
|
||||
width: $myW + $interiorMargin;
|
||||
input {
|
||||
width: $myW;
|
||||
}
|
||||
|
||||
@include complexFieldHolder(80px);
|
||||
}
|
||||
|
||||
.time.md {
|
||||
@include complexFieldHolder(60px);
|
||||
}
|
||||
|
||||
.time.sm {
|
||||
$myW: 40px;
|
||||
width: $myW + $interiorMargin;
|
||||
input {
|
||||
width: $myW;
|
||||
}
|
||||
@include complexFieldHolder(40px);
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,13 @@
|
||||
*****************************************************************************/
|
||||
.select {
|
||||
@include btnSubtle($colorSelectBg);
|
||||
margin: 0 0 2px 2px; // Needed to avoid dropshadow from being clipped by parent containers
|
||||
@if $shdwBtns != none {
|
||||
margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
|
||||
}
|
||||
padding: 0 $interiorMargin;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
line-height: $formInputH;
|
||||
select {
|
||||
@include appearance(none);
|
||||
@include box-sizing(border-box);
|
||||
@@ -40,11 +43,8 @@
|
||||
}
|
||||
&:after {
|
||||
@include contextArrow();
|
||||
pointer-events: none;
|
||||
color: rgba($colorSelectFg, percentToDecimal($contrastInvokeMenuPercent));
|
||||
//content:"v";
|
||||
//display: block;
|
||||
//font-family: 'symbolsfont';
|
||||
//pointer-events: none;
|
||||
position: absolute;
|
||||
right: $interiorMargin; top: 0;
|
||||
}
|
||||
|
||||
@@ -19,24 +19,45 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@-webkit-keyframes rotation {
|
||||
from {-webkit-transform: rotate(0deg);}
|
||||
to {-webkit-transform: rotate(359deg);}
|
||||
@include keyframes(rotation) {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(359deg); }
|
||||
}
|
||||
|
||||
@-moz-keyframes rotation {
|
||||
from {-moz-transform: rotate(0deg);}
|
||||
to {-moz-transform: rotate(359deg);}
|
||||
@mixin wait-spinner2($b: 5px, $c: $colorAlt1) {
|
||||
@include keyframes(rotateCentered) {
|
||||
0% { transform: translateX(-50%) translateY(-50%) rotate(0deg); }
|
||||
100% { 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);
|
||||
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;
|
||||
padding: 7%;
|
||||
left: 50%; top: 50%;
|
||||
}
|
||||
|
||||
@-o-keyframes rotation {
|
||||
from {-o-transform: rotate(0deg);}
|
||||
to {-o-transform: rotate(359deg);}
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
from {transform: rotate(0deg);}
|
||||
to {transform: rotate(359deg);}
|
||||
@mixin wait-spinner($b: 5px, $c: $colorAlt1) {
|
||||
display: block;
|
||||
position: absolute;
|
||||
-webkit-animation: rotation .6s infinite linear;
|
||||
-moz-animation: rotation .6s infinite linear;
|
||||
-o-animation: rotation .6s infinite linear;
|
||||
animation: rotation .6s infinite linear;
|
||||
border-color: rgba($c, 0.25);
|
||||
border-top-color: rgba($c, 1.0);
|
||||
border-style: solid;
|
||||
border-width: $b;
|
||||
@include border-radius(100%);
|
||||
}
|
||||
|
||||
.t-wait-spinner,
|
||||
@@ -96,4 +117,28 @@
|
||||
margin-top: 0 !important;
|
||||
padding: 0 !important;
|
||||
top: 0; left: 0;
|
||||
}
|
||||
|
||||
.loading {
|
||||
// Can be applied to any block element with height and width
|
||||
pointer-events: none;
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
}
|
||||
&:before {
|
||||
@include wait-spinner2(5px, $colorLoadingFg);
|
||||
z-index: 10;
|
||||
}
|
||||
&:after {
|
||||
@include absPosDefault();
|
||||
background: $colorLoadingBg;
|
||||
display: block;
|
||||
z-index: 9;
|
||||
}
|
||||
&.tree-item:before {
|
||||
padding: $menuLineH / 4;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,6 +40,11 @@ table {
|
||||
thead, .thead {
|
||||
border-bottom: 1px solid $colorTabHeaderBorder;
|
||||
}
|
||||
|
||||
&:not(.fixed-header) tr th {
|
||||
background-color: $colorTabHeaderBg;
|
||||
}
|
||||
|
||||
tbody, .tbody {
|
||||
display: table-row-group;
|
||||
tr, .tr {
|
||||
@@ -64,7 +69,6 @@ table {
|
||||
display: table-cell;
|
||||
}
|
||||
th, .th {
|
||||
background-color: $colorTabHeaderBg;
|
||||
border-left: 1px solid $colorTabHeaderBorder;
|
||||
color: $colorTabHeaderFg;
|
||||
padding: $tabularTdPadLR $tabularTdPadLR;
|
||||
@@ -143,7 +147,7 @@ table {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: $tabularHeaderH;
|
||||
background: rgba(#fff, 0.15);
|
||||
background-color: $colorTabHeaderBg;
|
||||
}
|
||||
}
|
||||
tbody, .tbody {
|
||||
|
||||
@@ -89,7 +89,7 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
.gl-plot-label,
|
||||
.l-plot-label {
|
||||
// @include test(yellow);
|
||||
color: lighten($colorBodyFg, 20%);
|
||||
color: $colorPlotLabelFg;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
// text-transform: uppercase;
|
||||
|
||||
@@ -214,8 +214,6 @@
|
||||
|
||||
.search-scroll {
|
||||
order: 3;
|
||||
|
||||
//padding-right: $rightPadding;
|
||||
margin-top: 4px;
|
||||
|
||||
// Adjustable scrolling size
|
||||
@@ -227,28 +225,6 @@
|
||||
|
||||
.load-icon {
|
||||
position: relative;
|
||||
&.loading {
|
||||
pointer-events: none;
|
||||
margin-left: $leftMargin;
|
||||
|
||||
.title-label {
|
||||
// Text styling
|
||||
font-style: italic;
|
||||
font-size: .9em;
|
||||
opacity: 0.5;
|
||||
|
||||
// Text positioning
|
||||
margin-left: $iconWidth + $leftMargin;
|
||||
line-height: 24px;
|
||||
}
|
||||
.wait-spinner {
|
||||
margin-left: $leftMargin;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.loading) {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.load-more-button {
|
||||
|
||||
@@ -83,7 +83,6 @@ ul.tree {
|
||||
.icon {
|
||||
&.l-icon-link,
|
||||
&.l-icon-alert {
|
||||
//@include txtShdw($shdwItemTreeIcon);
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -105,26 +104,12 @@ ul.tree {
|
||||
@include absPosDefault();
|
||||
display: block;
|
||||
left: $runningItemW + ($interiorMargin * 3);
|
||||
//right: $treeContextTriggerW + $interiorMargin;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
&.loading {
|
||||
pointer-events: none;
|
||||
.label {
|
||||
opacity: 0.5;
|
||||
.title-label {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
.wait-spinner {
|
||||
margin-left: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background: $colorItemTreeSelectedBg;
|
||||
color: $colorItemTreeSelectedFg;
|
||||
@@ -142,9 +127,6 @@ ul.tree {
|
||||
&:hover {
|
||||
background: rgba($colorBodyFg, 0.1); //lighten($colorBodyBg, 5%);
|
||||
color: pullForward($colorBodyFg, 20%);
|
||||
//.context-trigger {
|
||||
// display: block;
|
||||
//}
|
||||
.icon {
|
||||
color: $colorItemTreeIconHover;
|
||||
}
|
||||
@@ -158,7 +140,6 @@ ul.tree {
|
||||
|
||||
.context-trigger {
|
||||
$h: 0.9rem;
|
||||
//display: none;
|
||||
top: -1px;
|
||||
position: absolute;
|
||||
right: $interiorMarginSm;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
&.frame-template {
|
||||
.s-btn,
|
||||
.s-menu {
|
||||
.s-menu-btn {
|
||||
height: $ohH;
|
||||
line-height: $ohH;
|
||||
padding: 0 $interiorMargin;
|
||||
@@ -56,7 +56,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.s-menu:after {
|
||||
.s-menu-btn:after {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,22 +30,22 @@
|
||||
}
|
||||
|
||||
.holder-all {
|
||||
$myM: 0; // $interiorMarginSm;
|
||||
top: $myM;
|
||||
right: $myM;
|
||||
bottom: $myM;
|
||||
left: $myM;
|
||||
$myM: 0; // $interiorMarginSm;
|
||||
top: $myM;
|
||||
right: $myM;
|
||||
bottom: $myM;
|
||||
left: $myM;
|
||||
}
|
||||
|
||||
.browse-area,
|
||||
.edit-area,
|
||||
.editor {
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
//.editor {
|
||||
// @include border-radius($basicCr * 1.5);
|
||||
//}
|
||||
.editor {
|
||||
@include border-radius($basicCr * 1.5);
|
||||
}
|
||||
|
||||
.contents {
|
||||
$myM: 0; //$interiorMargin;
|
||||
@@ -68,8 +68,8 @@
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
&.abs {
|
||||
text-wrap: none;
|
||||
white-space: nowrap;
|
||||
text-wrap: none;
|
||||
white-space: nowrap;
|
||||
&.left,
|
||||
.left {
|
||||
width: 45%;
|
||||
@@ -95,67 +95,51 @@
|
||||
}
|
||||
|
||||
.user-environ {
|
||||
.browse-area,
|
||||
.edit-area,
|
||||
.editor {
|
||||
top: $bodyMargin + $ueTopBarH + ($interiorMargin);
|
||||
right: $bodyMargin;
|
||||
bottom: $ueFooterH + $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
}
|
||||
.browse-area,
|
||||
.edit-area,
|
||||
.editor {
|
||||
top: $bodyMargin + $ueTopBarH + ($interiorMargin);
|
||||
right: $bodyMargin;
|
||||
bottom: $ueFooterH + $bodyMargin;
|
||||
left: $bodyMargin;
|
||||
}
|
||||
|
||||
.browse-area,
|
||||
.edit-area {
|
||||
> .contents {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
.browse-area,
|
||||
.edit-area {
|
||||
> .contents {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-area {
|
||||
$tbH: $btnToolbarH + $interiorMargin;
|
||||
top: $bodyMargin + $ueTopBarEditH + ($interiorMargin);
|
||||
.tool-bar {
|
||||
bottom: auto;
|
||||
height: $tbH;
|
||||
line-height: $btnToolbarH;
|
||||
}
|
||||
.work-area {
|
||||
top: $tbH + $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
.edit-area {
|
||||
$tbH: $btnToolbarH + $interiorMargin;
|
||||
top: $bodyMargin + $ueTopBarEditH + ($interiorMargin);
|
||||
.tool-bar {
|
||||
bottom: auto;
|
||||
height: $tbH;
|
||||
line-height: $btnToolbarH;
|
||||
}
|
||||
.work-area {
|
||||
top: $tbH + $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
|
||||
// from _bottom-bar.scss
|
||||
.ue-bottom-bar {
|
||||
@include absPosDefault(0);// New status bar design
|
||||
top: auto;
|
||||
height: $ueFooterH;
|
||||
line-height: $ueFooterH - ($interiorMargin * 2);
|
||||
background: $colorFooterBg;
|
||||
color: lighten($colorBodyBg, 30%);
|
||||
font-size: .7rem;
|
||||
|
||||
.status-holder {
|
||||
@include box-sizing(border-box);
|
||||
@include absPosDefault($interiorMargin);
|
||||
@include ellipsize();
|
||||
//line-height: $ueFooterH - ($interiorMargin * 2);
|
||||
right: 120px;
|
||||
text-transform: uppercase;
|
||||
z-index: 1;
|
||||
}
|
||||
.app-logo {
|
||||
@include box-sizing(border-box);
|
||||
@include absPosDefault($interiorMargin);
|
||||
cursor: pointer;
|
||||
left: auto;
|
||||
width: $ueAppLogoW;
|
||||
z-index: 2;
|
||||
&.logo-openmctweb {
|
||||
background: url($dirImgs + 'logo-openmctweb.svg') no-repeat center center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ue-bottom-bar {
|
||||
//@include absPosDefault($bodyMargin);
|
||||
@include absPosDefault(0); // New status bar design
|
||||
top: auto;
|
||||
height: $ueFooterH;
|
||||
.status-holder {
|
||||
//right: $ueAppLogoW + $bodyMargin; New status bar design
|
||||
z-index: 1;
|
||||
}
|
||||
.app-logo {
|
||||
left: auto;
|
||||
width: $ueAppLogoW;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cols {
|
||||
@@ -241,89 +225,89 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.pane {
|
||||
position: absolute;
|
||||
&.treeview.left {
|
||||
.create-btn-holder {
|
||||
bottom: auto; top: 0;
|
||||
height: $ueTopBarH;
|
||||
.wrapper.menu-element {
|
||||
position: absolute;
|
||||
bottom: $interiorMargin;
|
||||
}
|
||||
}
|
||||
.search-holder {
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
}
|
||||
.tree-holder {
|
||||
overflow: auto;
|
||||
top: $ueTopBarH + $interiorMarginLg + $treeSearchInputBarH + $interiorMargin;
|
||||
}
|
||||
.create-btn-holder {
|
||||
bottom: auto;
|
||||
top: 0;
|
||||
height: $ueTopBarH;
|
||||
.wrapper.menu-element {
|
||||
position: absolute;
|
||||
bottom: $interiorMargin;
|
||||
}
|
||||
}
|
||||
.search-holder {
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
}
|
||||
.tree-holder {
|
||||
overflow: auto;
|
||||
top: $ueTopBarH + $interiorMarginLg + $treeSearchInputBarH + $interiorMargin;
|
||||
}
|
||||
}
|
||||
&.items {
|
||||
.object-browse-bar {
|
||||
.left.abs,
|
||||
.right.abs {
|
||||
top: auto;
|
||||
}
|
||||
//.left.abs {
|
||||
// @include tmpBorder(green);
|
||||
//}
|
||||
//.right.abs {
|
||||
// @include tmpBorder(red);
|
||||
//}
|
||||
}
|
||||
.object-holder {
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
.left.abs,
|
||||
.right.abs {
|
||||
top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
.object-holder {
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.split-layout {
|
||||
&.horizontal {
|
||||
// Slides up and down
|
||||
>.pane {
|
||||
// @include test();
|
||||
margin-top: $interiorMargin;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.vertical {
|
||||
// Slides left and right
|
||||
>.pane {
|
||||
// @include test();
|
||||
margin-left: $interiorMargin;
|
||||
>.holder {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
.holder {
|
||||
right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.horizontal {
|
||||
// Slides up and down
|
||||
> .pane {
|
||||
// @include test();
|
||||
margin-top: $interiorMargin;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.vertical {
|
||||
// Slides left and right
|
||||
> .pane {
|
||||
// @include test();
|
||||
margin-left: $interiorMargin;
|
||||
> .holder {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
.holder {
|
||||
right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.object-holder {
|
||||
overflow: hidden; // Contained objects need to handle their own overflow now
|
||||
top: $ueTopBarH + $interiorMarginLg;
|
||||
> ng-include {
|
||||
@include absPosDefault(0, auto);
|
||||
}
|
||||
&.l-controls-visible {
|
||||
&.l-time-controller-visible {
|
||||
bottom: nth($ueTimeControlH,1) + nth($ueTimeControlH,2) +nth($ueTimeControlH,3) + ($interiorMargin * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.object-browse-bar .s-btn,
|
||||
.top-bar .buttons-main .s-btn,
|
||||
.top-bar .s-menu,
|
||||
.top-bar .s-menu-btn,
|
||||
.tool-bar .s-btn,
|
||||
.tool-bar .s-menu {
|
||||
$h: $btnToolbarH;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
vertical-align: top;
|
||||
.tool-bar .s-menu-btn {
|
||||
$h: $btnToolbarH;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.object-browse-bar,
|
||||
@@ -334,33 +318,29 @@
|
||||
}
|
||||
|
||||
.object-browse-bar {
|
||||
//@include test(blue);
|
||||
@include absPosDefault(0, visible);
|
||||
@include box-sizing(border-box);
|
||||
height: $ueTopBarH;
|
||||
line-height: $ueTopBarH;
|
||||
white-space: nowrap;
|
||||
//@include test(blue);
|
||||
@include absPosDefault(0, visible);
|
||||
@include box-sizing(border-box);
|
||||
height: $ueTopBarH;
|
||||
line-height: $ueTopBarH;
|
||||
white-space: nowrap;
|
||||
|
||||
.left {
|
||||
padding-right: $interiorMarginLg * 2;
|
||||
.l-back {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
padding-right: $interiorMarginLg * 2;
|
||||
.l-back {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.l-flex {
|
||||
@include webkitVal('display', 'flex');
|
||||
@include webkitProp('flex-flow', 'row nowrap');
|
||||
.left {
|
||||
//@include test(red);
|
||||
@include webkitProp(flex, '1 1 0');
|
||||
padding-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
|
||||
.vscroll {
|
||||
overflow-y: auto;
|
||||
}
|
||||
@include webkitVal('display', 'flex');
|
||||
@include webkitProp('flex-flow', 'row nowrap');
|
||||
.left {
|
||||
//@include test(red);
|
||||
@include webkitProp(flex, '1 1 0');
|
||||
padding-right: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT Web includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<div ng-controller="DateTimePickerController" class="l-datetime-picker s-datetime-picker s-menu">
|
||||
<div class="holder">
|
||||
<div class="l-month-year-pager">
|
||||
<a class="pager prev" ng-click="changeMonth(-1)"></a>
|
||||
<span class="val">{{month}} {{year}}</span>
|
||||
<a class="pager next" ng-click="changeMonth(1)"></a>
|
||||
</div>
|
||||
<div class="l-calendar">
|
||||
<ul class="l-cal-row l-header">
|
||||
<li ng-repeat="day in ['Su','Mo','Tu','We','Th','Fr','Sa']">{{day}}</li>
|
||||
</ul>
|
||||
<ul class="l-cal-row l-body" ng-repeat="row in table">
|
||||
<li ng-repeat="cell in row"
|
||||
ng-click="select(cell)"
|
||||
ng-class='{ "in-month": isInCurrentMonth(cell), selected: isSelected(cell) }'>
|
||||
<div class="prime">{{cell.day}}</div>
|
||||
<div class="sub">{{cell.dayOfYear}}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-time-selects complex datetime"
|
||||
ng-show="options">
|
||||
<div class="field-hints">
|
||||
<span class="hint time md"
|
||||
ng-repeat="key in ['hours', 'minutes', 'seconds']"
|
||||
ng-if="options[key]">
|
||||
{{nameFor(key)}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="field control time md"
|
||||
ng-repeat="key in ['hours', 'minutes', 'seconds']"
|
||||
ng-if="options[key]">
|
||||
<div class='form-control select'>
|
||||
<select size="1"
|
||||
ng-model="time[key]"
|
||||
ng-options="i for i in optionsFor(key)">
|
||||
</select>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<span ng-controller="ViewSwitcherController">
|
||||
<div
|
||||
class="view-switcher menu-element s-menu"
|
||||
class="view-switcher menu-element s-menu-btn"
|
||||
ng-if="view.length > 1"
|
||||
ng-controller="ClickAwayController as toggle"
|
||||
>
|
||||
|
||||
@@ -1,69 +1,108 @@
|
||||
<!--
|
||||
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.
|
||||
|
||||
NOTES
|
||||
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.
|
||||
|
||||
Ticks:
|
||||
The thinking is to divide whatever the current time span is by 5,
|
||||
and assign values accordingly to 5 statically-positioned ticks. So the tick x-position is a static percentage
|
||||
of the total width available, and the labels change dynamically. This is consistent
|
||||
with our current approach to the time axis of plots.
|
||||
I'm keeping the number of ticks low so that when the view portal gets narrow,
|
||||
the tick labels won't collide with each other. For extra credit, add/remove ticks as the user resizes the view area.
|
||||
Note: this eval needs to be based on the whatever is containing the
|
||||
time-controller component, not the whole browser window.
|
||||
|
||||
Range indicator and slider knobs:
|
||||
The left and right properties used in .slider .range-holder and the .knobs are
|
||||
CSS offsets from the left and right of their respective containers. You
|
||||
may want or need to calculate those positions as pure offsets from the start datetime
|
||||
(or left, as it were) and set them as left properties. No problem if so, but
|
||||
we'll need to tweak the CSS tiny bit to get the center of the knobs to line up
|
||||
properly on the range left and right bounds.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT Web includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-controller="TimeRangeController">
|
||||
<div class="l-time-range-inputs-holder">
|
||||
<span class="l-time-range-inputs-elem ui-symbol type-icon">C</span>
|
||||
<span class="l-time-range-input" ng-controller="ToggleController as t1">
|
||||
<!--<span class="lbl">Start</span>-->
|
||||
<span class="s-btn time-range-start">
|
||||
<input type="text"
|
||||
ng-model="boundsModel.start"
|
||||
ng-class="{ error: !boundsModel.startValid }">
|
||||
</input>
|
||||
<a class="ui-symbol icon icon-calendar" ng-click="t1.toggle()"></a>
|
||||
<mct-popup ng-if="t1.isActive()">
|
||||
<div mct-click-elsewhere="t1.setState(false)">
|
||||
<mct-control key="'datetime-picker'"
|
||||
ng-model="ngModel.outer"
|
||||
field="'start'"
|
||||
options="{ hours: true }">
|
||||
</mct-control>
|
||||
</div>
|
||||
</mct-popup>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div ng-init="
|
||||
notes = 'Temporarily using an array to populate ticks so I can see what I\'m doing';
|
||||
ticks = [
|
||||
'00:00',
|
||||
'00:30',
|
||||
'01:00',
|
||||
'01:30',
|
||||
'02:00'
|
||||
];
|
||||
"></div>
|
||||
<span class="l-time-range-inputs-elem lbl">to</span>
|
||||
|
||||
<div class="l-time-controller">
|
||||
<div class="l-time-range-inputs-holder">
|
||||
Start: <input type="date" />
|
||||
End: <input type="date" />
|
||||
</div>
|
||||
<span class="l-time-range-input" ng-controller="ToggleController as t2">
|
||||
<!--<span class="lbl">End</span>-->
|
||||
<span class="s-btn l-time-range-input">
|
||||
<input type="text"
|
||||
ng-model="boundsModel.end"
|
||||
ng-class="{ error: !boundsModel.endValid }">
|
||||
</input>
|
||||
<a class="ui-symbol icon icon-calendar" ng-click="t2.toggle()">
|
||||
</a>
|
||||
<mct-popup ng-if="t2.isActive()">
|
||||
<div mct-click-elsewhere="t2.setState(false)">
|
||||
<mct-control key="'datetime-picker'"
|
||||
ng-model="ngModel.outer"
|
||||
field="'end'"
|
||||
options="{ hours: true }">
|
||||
</mct-control>
|
||||
</div>
|
||||
</mct-popup>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="l-time-range-slider-holder">
|
||||
<div class="l-time-range-slider">
|
||||
<div class="slider">
|
||||
<div class="slot range-holder">
|
||||
<div class="range" style="left: 0%; right: 30%;"></div>
|
||||
</div>
|
||||
<div class="knob knob-l" style="left: 0%;">
|
||||
<div class="range-value">05/22 14:46</div>
|
||||
</div>
|
||||
<div class="knob knob-r" style="right: 30%;">
|
||||
<div class="range-value">07/22 01:21</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-time-range-slider-holder">
|
||||
<div class="l-time-range-slider">
|
||||
<div class="slider"
|
||||
mct-resize="spanWidth = bounds.width">
|
||||
<div class="knob knob-l"
|
||||
mct-drag-down="startLeftDrag()"
|
||||
mct-drag="leftDrag(delta[0])"
|
||||
ng-style="{ left: startInnerPct }">
|
||||
<div class="range-value">{{startInnerText}}</div>
|
||||
</div>
|
||||
<div class="knob knob-r"
|
||||
mct-drag-down="startRightDrag()"
|
||||
mct-drag="rightDrag(delta[0])"
|
||||
ng-style="{ right: endInnerPct }">
|
||||
<div class="range-value">{{endInnerText}}</div>
|
||||
</div>
|
||||
<div class="slot range-holder">
|
||||
<div class="range"
|
||||
mct-drag-down="startMiddleDrag()"
|
||||
mct-drag="middleDrag(delta[0])"
|
||||
ng-style="{ left: startInnerPct, right: endInnerPct}">
|
||||
<div class="toi-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="l-time-range-ticks-holder">
|
||||
<div class="l-time-range-ticks">
|
||||
<div
|
||||
ng-repeat="tick in ticks"
|
||||
ng-style="{ left: $index * 25 + '%' }"
|
||||
class="tick tick-x"
|
||||
>
|
||||
<span class="l-time-range-tick-label">{{tick}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-time-range-ticks-holder">
|
||||
<div class="l-time-range-ticks">
|
||||
<div
|
||||
ng-repeat="tick in ticks"
|
||||
ng-style="{ left: $index * (100 / (ticks.length - 1)) + '%' }"
|
||||
class="tick tick-x"
|
||||
>
|
||||
<span class="l-time-range-tick-label">{{tick}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
[ 'moment' ],
|
||||
function (moment) {
|
||||
'use strict';
|
||||
|
||||
var TIME_NAMES = {
|
||||
'hours': "Hour",
|
||||
'minutes': "Minute",
|
||||
'seconds': "Second"
|
||||
},
|
||||
MONTHS = moment.months(),
|
||||
TIME_OPTIONS = (function makeRanges() {
|
||||
var arr = [];
|
||||
while (arr.length < 60) {
|
||||
arr.push(arr.length);
|
||||
}
|
||||
return {
|
||||
hours: arr.slice(0, 24),
|
||||
minutes: arr,
|
||||
seconds: arr
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* Controller to support the date-time picker.
|
||||
*
|
||||
* Adds/uses the following properties in scope:
|
||||
* * `year`: Year being displayed in picker
|
||||
* * `month`: Month being displayed
|
||||
* * `table`: Table being displayed; array of arrays of
|
||||
* * `day`: Day of month
|
||||
* * `dayOfYear`: Day of year
|
||||
* * `month`: Month associated with the day
|
||||
* * `year`: Year associated with the day.
|
||||
* * `date`: Date chosen
|
||||
* * `year`: Year selected
|
||||
* * `month`: Month selected (0-indexed)
|
||||
* * `day`: Day of month selected
|
||||
* * `time`: Chosen time (hours/minutes/seconds)
|
||||
* * `hours`: Hours chosen
|
||||
* * `minutes`: Minutes chosen
|
||||
* * `seconds`: Seconds chosen
|
||||
*
|
||||
* Months are zero-indexed, day-of-months are one-indexed.
|
||||
*/
|
||||
function DateTimePickerController($scope, now) {
|
||||
var year,
|
||||
month, // For picker state, not model state
|
||||
interacted = false;
|
||||
|
||||
function generateTable() {
|
||||
var m = moment.utc({ year: year, month: month }).day(0),
|
||||
table = [],
|
||||
row,
|
||||
col;
|
||||
|
||||
for (row = 0; row < 6; row += 1) {
|
||||
table.push([]);
|
||||
for (col = 0; col < 7; col += 1) {
|
||||
table[row].push({
|
||||
year: m.year(),
|
||||
month: m.month(),
|
||||
day: m.date(),
|
||||
dayOfYear: m.dayOfYear()
|
||||
});
|
||||
m.add(1, 'days'); // Next day!
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
function updateScopeForMonth() {
|
||||
$scope.month = MONTHS[month];
|
||||
$scope.year = year;
|
||||
$scope.table = generateTable();
|
||||
}
|
||||
|
||||
function updateFromModel(ngModel) {
|
||||
var m;
|
||||
|
||||
m = moment.utc(ngModel);
|
||||
|
||||
$scope.date = {
|
||||
year: m.year(),
|
||||
month: m.month(),
|
||||
day: m.date()
|
||||
};
|
||||
$scope.time = {
|
||||
hours: m.hour(),
|
||||
minutes: m.minute(),
|
||||
seconds: m.second()
|
||||
};
|
||||
|
||||
//window.alert($scope.date.day + " " + ngModel);
|
||||
|
||||
// Zoom to that date in the picker, but
|
||||
// only if the user hasn't interacted with it yet.
|
||||
if (!interacted) {
|
||||
year = m.year();
|
||||
month = m.month();
|
||||
updateScopeForMonth();
|
||||
}
|
||||
}
|
||||
|
||||
function updateFromView() {
|
||||
var m = moment.utc({
|
||||
year: $scope.date.year,
|
||||
month: $scope.date.month,
|
||||
day: $scope.date.day,
|
||||
hour: $scope.time.hours,
|
||||
minute: $scope.time.minutes,
|
||||
second: $scope.time.seconds
|
||||
});
|
||||
$scope.ngModel[$scope.field] = m.valueOf();
|
||||
}
|
||||
|
||||
$scope.isInCurrentMonth = function (cell) {
|
||||
return cell.month === month;
|
||||
};
|
||||
|
||||
$scope.isSelected = function (cell) {
|
||||
var date = $scope.date || {};
|
||||
return cell.day === date.day &&
|
||||
cell.month === date.month &&
|
||||
cell.year === date.year;
|
||||
};
|
||||
|
||||
$scope.select = function (cell) {
|
||||
$scope.date = $scope.date || {};
|
||||
$scope.date.month = cell.month;
|
||||
$scope.date.year = cell.year;
|
||||
$scope.date.day = cell.day;
|
||||
updateFromView();
|
||||
};
|
||||
|
||||
$scope.dateEquals = function (d1, d2) {
|
||||
return d1.year === d2.year &&
|
||||
d1.month === d2.month &&
|
||||
d1.day === d2.day;
|
||||
};
|
||||
|
||||
$scope.changeMonth = function (delta) {
|
||||
month += delta;
|
||||
if (month > 11) {
|
||||
month = 0;
|
||||
year += 1;
|
||||
}
|
||||
if (month < 0) {
|
||||
month = 11;
|
||||
year -= 1;
|
||||
}
|
||||
interacted = true;
|
||||
updateScopeForMonth();
|
||||
};
|
||||
|
||||
$scope.nameFor = function (key) {
|
||||
return TIME_NAMES[key];
|
||||
};
|
||||
|
||||
$scope.optionsFor = function (key) {
|
||||
return TIME_OPTIONS[key];
|
||||
};
|
||||
|
||||
updateScopeForMonth();
|
||||
|
||||
// Ensure some useful default
|
||||
$scope.ngModel[$scope.field] =
|
||||
$scope.ngModel[$scope.field] === undefined ?
|
||||
now() : $scope.ngModel[$scope.field];
|
||||
|
||||
$scope.$watch('ngModel[field]', updateFromModel);
|
||||
$scope.$watchCollection('date', updateFromView);
|
||||
$scope.$watchCollection('time', updateFromView);
|
||||
}
|
||||
|
||||
return DateTimePickerController;
|
||||
}
|
||||
);
|
||||
302
platform/commonUI/general/src/controllers/TimeRangeController.js
Normal file
302
platform/commonUI/general/src/controllers/TimeRangeController.js
Normal file
@@ -0,0 +1,302 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['moment'],
|
||||
function (moment) {
|
||||
"use strict";
|
||||
|
||||
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss",
|
||||
TICK_SPACING_PX = 150;
|
||||
|
||||
/**
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function TimeConductorController($scope, now) {
|
||||
var tickCount = 2,
|
||||
innerMinimumSpan = 1000, // 1 second
|
||||
outerMinimumSpan = 1000 * 60 * 60, // 1 hour
|
||||
initialDragValue;
|
||||
|
||||
function formatTimestamp(ts) {
|
||||
return moment.utc(ts).format(DATE_FORMAT);
|
||||
}
|
||||
|
||||
function parseTimestamp(text) {
|
||||
var m = moment.utc(text, DATE_FORMAT);
|
||||
if (m.isValid()) {
|
||||
return m.valueOf();
|
||||
} else {
|
||||
throw new Error("Could not parse " + text);
|
||||
}
|
||||
}
|
||||
|
||||
// From 0.0-1.0 to "0%"-"1%"
|
||||
function toPercent(p) {
|
||||
return (100 * p) + "%";
|
||||
}
|
||||
|
||||
function updateTicks() {
|
||||
var i, p, ts, start, end, span;
|
||||
end = $scope.ngModel.outer.end;
|
||||
start = $scope.ngModel.outer.start;
|
||||
span = end - start;
|
||||
$scope.ticks = [];
|
||||
for (i = 0; i < tickCount; i += 1) {
|
||||
p = i / (tickCount - 1);
|
||||
ts = p * span + start;
|
||||
$scope.ticks.push(formatTimestamp(ts));
|
||||
}
|
||||
}
|
||||
|
||||
function updateSpanWidth(w) {
|
||||
tickCount = Math.max(Math.floor(w / TICK_SPACING_PX), 2);
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
function updateViewForInnerSpanFromModel(ngModel) {
|
||||
var span = ngModel.outer.end - ngModel.outer.start;
|
||||
|
||||
// Expose readable dates for the knobs
|
||||
$scope.startInnerText = formatTimestamp(ngModel.inner.start);
|
||||
$scope.endInnerText = formatTimestamp(ngModel.inner.end);
|
||||
|
||||
// And positions for the knobs
|
||||
$scope.startInnerPct =
|
||||
toPercent((ngModel.inner.start - ngModel.outer.start) / span);
|
||||
$scope.endInnerPct =
|
||||
toPercent((ngModel.outer.end - ngModel.inner.end) / span);
|
||||
}
|
||||
|
||||
function defaultBounds() {
|
||||
var t = now();
|
||||
return {
|
||||
start: t - 24 * 3600 * 1000, // One day
|
||||
end: t
|
||||
};
|
||||
}
|
||||
|
||||
function copyBounds(bounds) {
|
||||
return { start: bounds.start, end: bounds.end };
|
||||
}
|
||||
|
||||
function updateBoundsTextForProperty(ngModel, property) {
|
||||
try {
|
||||
if (!$scope.boundsModel[property] ||
|
||||
parseTimestamp($scope.boundsModel[property]) !==
|
||||
ngModel.outer[property]) {
|
||||
$scope.boundsModel[property] =
|
||||
formatTimestamp(ngModel.outer[property]);
|
||||
}
|
||||
} catch (e) {
|
||||
// User-entered text is invalid, so leave it be
|
||||
// until they fix it.
|
||||
}
|
||||
}
|
||||
|
||||
function updateBoundsText(ngModel) {
|
||||
updateBoundsTextForProperty(ngModel, 'start');
|
||||
updateBoundsTextForProperty(ngModel, 'end');
|
||||
}
|
||||
|
||||
function updateViewFromModel(ngModel) {
|
||||
var t = now();
|
||||
|
||||
ngModel = ngModel || {};
|
||||
ngModel.outer = ngModel.outer || defaultBounds();
|
||||
ngModel.inner = ngModel.inner || copyBounds(ngModel.outer);
|
||||
|
||||
// First, dates for the date pickers for outer bounds
|
||||
updateBoundsText(ngModel);
|
||||
|
||||
// Then various updates for the inner span
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
|
||||
// Stick it back is scope (in case we just set defaults)
|
||||
$scope.ngModel = ngModel;
|
||||
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
function startLeftDrag() {
|
||||
initialDragValue = $scope.ngModel.inner.start;
|
||||
}
|
||||
|
||||
function startRightDrag() {
|
||||
initialDragValue = $scope.ngModel.inner.end;
|
||||
}
|
||||
|
||||
function startMiddleDrag() {
|
||||
initialDragValue = {
|
||||
start: $scope.ngModel.inner.start,
|
||||
end: $scope.ngModel.inner.end
|
||||
};
|
||||
}
|
||||
|
||||
function toMillis(pixels) {
|
||||
var span = $scope.ngModel.outer.end - $scope.ngModel.outer.start;
|
||||
return (pixels / $scope.spanWidth) * span;
|
||||
}
|
||||
|
||||
function clamp(value, low, high) {
|
||||
return Math.max(low, Math.min(high, value));
|
||||
}
|
||||
|
||||
function leftDrag(pixels) {
|
||||
var delta = toMillis(pixels);
|
||||
$scope.ngModel.inner.start = clamp(
|
||||
initialDragValue + delta,
|
||||
$scope.ngModel.outer.start,
|
||||
$scope.ngModel.inner.end - innerMinimumSpan
|
||||
);
|
||||
updateViewFromModel($scope.ngModel);
|
||||
}
|
||||
|
||||
function rightDrag(pixels) {
|
||||
var delta = toMillis(pixels);
|
||||
$scope.ngModel.inner.end = clamp(
|
||||
initialDragValue + delta,
|
||||
$scope.ngModel.inner.start + innerMinimumSpan,
|
||||
$scope.ngModel.outer.end
|
||||
);
|
||||
updateViewFromModel($scope.ngModel);
|
||||
}
|
||||
|
||||
function middleDrag(pixels) {
|
||||
var delta = toMillis(pixels),
|
||||
edge = delta < 0 ? 'start' : 'end',
|
||||
opposite = delta < 0 ? 'end' : 'start';
|
||||
|
||||
// Adjust the position of the edge in the direction of drag
|
||||
$scope.ngModel.inner[edge] = clamp(
|
||||
initialDragValue[edge] + delta,
|
||||
$scope.ngModel.outer.start,
|
||||
$scope.ngModel.outer.end
|
||||
);
|
||||
// Adjust opposite knob to maintain span
|
||||
$scope.ngModel.inner[opposite] = $scope.ngModel.inner[edge] +
|
||||
initialDragValue[opposite] - initialDragValue[edge];
|
||||
|
||||
updateViewFromModel($scope.ngModel);
|
||||
}
|
||||
|
||||
function updateOuterStart(t) {
|
||||
var ngModel = $scope.ngModel;
|
||||
|
||||
ngModel.outer.start = t;
|
||||
|
||||
ngModel.outer.end = Math.max(
|
||||
ngModel.outer.start + outerMinimumSpan,
|
||||
ngModel.outer.end
|
||||
);
|
||||
|
||||
ngModel.inner.start =
|
||||
Math.max(ngModel.outer.start, ngModel.inner.start);
|
||||
ngModel.inner.end = Math.max(
|
||||
ngModel.inner.start + innerMinimumSpan,
|
||||
ngModel.inner.end
|
||||
);
|
||||
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
function updateOuterEnd(t) {
|
||||
var ngModel = $scope.ngModel;
|
||||
|
||||
ngModel.outer.end = t;
|
||||
|
||||
ngModel.outer.start = Math.min(
|
||||
ngModel.outer.end - outerMinimumSpan,
|
||||
ngModel.outer.start
|
||||
);
|
||||
|
||||
ngModel.inner.end =
|
||||
Math.min(ngModel.outer.end, ngModel.inner.end);
|
||||
ngModel.inner.start = Math.min(
|
||||
ngModel.inner.end - innerMinimumSpan,
|
||||
ngModel.inner.start
|
||||
);
|
||||
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
function updateStartFromText(value) {
|
||||
try {
|
||||
updateOuterStart(parseTimestamp(value));
|
||||
updateBoundsTextForProperty($scope.ngModel, 'end');
|
||||
$scope.boundsModel.startValid = true;
|
||||
} catch (e) {
|
||||
$scope.boundsModel.startValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function updateEndFromText(value) {
|
||||
try {
|
||||
updateOuterEnd(parseTimestamp(value));
|
||||
updateBoundsTextForProperty($scope.ngModel, 'start');
|
||||
$scope.boundsModel.endValid = true;
|
||||
} catch (e) {
|
||||
$scope.boundsModel.endValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function updateStartFromPicker(value) {
|
||||
updateOuterStart(value);
|
||||
updateBoundsText($scope.ngModel);
|
||||
}
|
||||
|
||||
function updateEndFromPicker(value) {
|
||||
updateOuterEnd(value);
|
||||
updateBoundsText($scope.ngModel);
|
||||
}
|
||||
|
||||
$scope.startLeftDrag = startLeftDrag;
|
||||
$scope.startRightDrag = startRightDrag;
|
||||
$scope.startMiddleDrag = startMiddleDrag;
|
||||
$scope.leftDrag = leftDrag;
|
||||
$scope.rightDrag = rightDrag;
|
||||
$scope.middleDrag = middleDrag;
|
||||
|
||||
$scope.state = false;
|
||||
$scope.ticks = [];
|
||||
$scope.boundsModel = {};
|
||||
|
||||
// Initialize scope to defaults
|
||||
updateViewFromModel($scope.ngModel);
|
||||
|
||||
$scope.$watchCollection("ngModel", updateViewFromModel);
|
||||
$scope.$watch("spanWidth", updateSpanWidth);
|
||||
$scope.$watch("ngModel.outer.start", updateStartFromPicker);
|
||||
$scope.$watch("ngModel.outer.end", updateEndFromPicker);
|
||||
$scope.$watch("boundsModel.start", updateStartFromText);
|
||||
$scope.$watch("boundsModel.end", updateEndFromText);
|
||||
}
|
||||
|
||||
return TimeConductorController;
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,77 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The `mct-click-elsewhere` directive will evaluate its
|
||||
* associated expression whenever a `mousedown` occurs anywhere
|
||||
* outside of the element that has the `mct-click-elsewhere`
|
||||
* directive attached. This is useful for dismissing popups
|
||||
* and the like.
|
||||
*/
|
||||
function MCTClickElsewhere($document) {
|
||||
|
||||
// Link; install event handlers.
|
||||
function link(scope, element, attrs) {
|
||||
// Keep a reference to the body, to attach/detach
|
||||
// mouse event handlers; mousedown and mouseup cannot
|
||||
// only be attached to the element being linked, as the
|
||||
// mouse may leave this element during the drag.
|
||||
var body = $document.find('body');
|
||||
|
||||
function clickBody(event) {
|
||||
var x = event.clientX,
|
||||
y = event.clientY,
|
||||
rect = element[0].getBoundingClientRect(),
|
||||
xMin = rect.left,
|
||||
xMax = xMin + rect.width,
|
||||
yMin = rect.top,
|
||||
yMax = yMin + rect.height;
|
||||
|
||||
if (x < xMin || x > xMax || y < yMin || y > yMax) {
|
||||
scope.$eval(attrs.mctClickElsewhere);
|
||||
}
|
||||
}
|
||||
|
||||
body.on("mousedown", clickBody);
|
||||
scope.$on("$destroy", function () {
|
||||
body.off("mousedown", clickBody);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// mct-drag only makes sense as an attribute
|
||||
restrict: "A",
|
||||
// Link function, to install event handlers
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTClickElsewhere;
|
||||
}
|
||||
);
|
||||
|
||||
73
platform/commonUI/general/src/directives/MCTPopup.js
Normal file
73
platform/commonUI/general/src/directives/MCTPopup.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************
|
||||
* 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 TEMPLATE = "<div></div>";
|
||||
|
||||
/**
|
||||
* The `mct-popup` directive may be used to display elements
|
||||
* which "pop up" over other parts of the page. Typically, this is
|
||||
* done in conjunction with an `ng-if` to control the visibility
|
||||
* of the popup.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* <mct-popup ng-if="someExpr">
|
||||
* <span>These are the contents of the popup!</span>
|
||||
* </mct-popup>
|
||||
*
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/general
|
||||
* @param $compile Angular's $compile service
|
||||
* @param {platform/commonUI/general.PopupService} popupService
|
||||
*/
|
||||
function MCTPopup($compile, popupService) {
|
||||
function link(scope, element, attrs, ctrl, transclude) {
|
||||
var div = $compile(TEMPLATE)(scope),
|
||||
rect = element.parent()[0].getBoundingClientRect(),
|
||||
position = [ rect.left, rect.top ],
|
||||
popup = popupService.display(div, position);
|
||||
|
||||
transclude(function (clone) {
|
||||
div.append(clone);
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function () {
|
||||
popup.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "E",
|
||||
transclude: true,
|
||||
link: link,
|
||||
scope: {}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTPopup;
|
||||
}
|
||||
);
|
||||
@@ -58,6 +58,7 @@ define(
|
||||
// Link; start listening for changes to an element's size
|
||||
function link(scope, element, attrs) {
|
||||
var lastBounds,
|
||||
linking = true,
|
||||
active = true;
|
||||
|
||||
// Determine how long to wait before the next update
|
||||
@@ -74,7 +75,9 @@ define(
|
||||
lastBounds.width !== bounds.width ||
|
||||
lastBounds.height !== bounds.height) {
|
||||
scope.$eval(attrs.mctResize, { bounds: bounds });
|
||||
scope.$apply(); // Trigger a digest
|
||||
if (!linking) { // Avoid apply-in-a-digest
|
||||
scope.$apply();
|
||||
}
|
||||
lastBounds = bounds;
|
||||
}
|
||||
}
|
||||
@@ -101,6 +104,9 @@ define(
|
||||
|
||||
// Handle the initial callback
|
||||
onInterval();
|
||||
|
||||
// Trigger scope.$apply on subsequent changes
|
||||
linking = false;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
89
platform/commonUI/general/src/services/Popup.js
Normal file
89
platform/commonUI/general/src/services/Popup.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/*****************************************************************************
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* A popup is an element that has been displayed at a particular
|
||||
* location within the page.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/general
|
||||
* @param element the jqLite-wrapped element
|
||||
* @param {object} styles an object containing key-value pairs
|
||||
* of styles used to position the element.
|
||||
*/
|
||||
function Popup(element, styles) {
|
||||
this.styles = styles;
|
||||
this.element = element;
|
||||
|
||||
element.css(styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop showing this popup.
|
||||
*/
|
||||
Popup.prototype.dismiss = function () {
|
||||
this.element.remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears to the
|
||||
* left of its original location.
|
||||
* @returns {boolean} true if the popup goes left
|
||||
*/
|
||||
Popup.prototype.goesLeft = function () {
|
||||
return !this.styles.left;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears to the
|
||||
* right of its original location.
|
||||
* @returns {boolean} true if the popup goes right
|
||||
*/
|
||||
Popup.prototype.goesRight = function () {
|
||||
return !this.styles.right;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears above
|
||||
* its original location.
|
||||
* @returns {boolean} true if the popup goes up
|
||||
*/
|
||||
Popup.prototype.goesUp = function () {
|
||||
return !this.styles.top;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this popup is positioned such that it appears below
|
||||
* its original location.
|
||||
* @returns {boolean} true if the popup goes down
|
||||
*/
|
||||
Popup.prototype.goesDown = function () {
|
||||
return !this.styles.bottom;
|
||||
};
|
||||
|
||||
return Popup;
|
||||
}
|
||||
);
|
||||
127
platform/commonUI/general/src/services/PopupService.js
Normal file
127
platform/commonUI/general/src/services/PopupService.js
Normal file
@@ -0,0 +1,127 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./Popup'],
|
||||
function (Popup) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Displays popup elements at specific positions within the document.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function PopupService($document, $window) {
|
||||
this.$document = $document;
|
||||
this.$window = $window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options controlling how the popup is displaed.
|
||||
*
|
||||
* @typedef PopupOptions
|
||||
* @memberof platform/commonUI/general
|
||||
* @property {number} [offsetX] the horizontal distance, in pixels,
|
||||
* to offset the element in whichever direction it is
|
||||
* displayed. Defaults to 0.
|
||||
* @property {number} [offsetY] the vertical distance, in pixels,
|
||||
* to offset the element in whichever direction it is
|
||||
* displayed. Defaults to 0.
|
||||
* @property {number} [marginX] the horizontal position, in pixels,
|
||||
* after which to prefer to display the element to the left.
|
||||
* If negative, this is relative to the right edge of the
|
||||
* page. Defaults to half the window's width.
|
||||
* @property {number} [marginY] the vertical position, in pixels,
|
||||
* after which to prefer to display the element upward.
|
||||
* If negative, this is relative to the right edge of the
|
||||
* page. Defaults to half the window's height.
|
||||
* @property {string} [leftClass] class to apply when shifting to the left
|
||||
* @property {string} [rightClass] class to apply when shifting to the right
|
||||
* @property {string} [upClass] class to apply when shifting upward
|
||||
* @property {string} [downClass] class to apply when shifting downward
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display a popup at a particular location. The location chosen will
|
||||
* be the corner of the element; the element will be positioned either
|
||||
* to the left or the right of this point depending on available
|
||||
* horizontal space, and will similarly be shifted upward or downward
|
||||
* depending on available vertical space.
|
||||
*
|
||||
* @param element the jqLite-wrapped DOM element to pop up
|
||||
* @param {number[]} position x,y position of the element, in
|
||||
* pixel coordinates. Negative values are interpreted as
|
||||
* relative to the right or bottom of the window.
|
||||
* @param {PopupOptions} [options] additional options to control
|
||||
* positioning of the popup
|
||||
* @returns {platform/commonUI/general.Popup} the popup
|
||||
*/
|
||||
PopupService.prototype.display = function (element, position, options) {
|
||||
var $document = this.$document,
|
||||
$window = this.$window,
|
||||
body = $document.find('body'),
|
||||
winDim = [ $window.innerWidth, $window.innerHeight ],
|
||||
styles = { position: 'absolute' },
|
||||
margin,
|
||||
offset,
|
||||
bubble;
|
||||
|
||||
function adjustNegatives(value, index) {
|
||||
return value < 0 ? (value + winDim[index]) : value;
|
||||
}
|
||||
|
||||
// Defaults
|
||||
options = options || {};
|
||||
offset = [
|
||||
options.offsetX !== undefined ? options.offsetX : 0,
|
||||
options.offsetY !== undefined ? options.offsetY : 0
|
||||
];
|
||||
margin = [ options.marginX, options.marginY ].map(function (m, i) {
|
||||
return m === undefined ? (winDim[i] / 2) : m;
|
||||
}).map(adjustNegatives);
|
||||
|
||||
position = position.map(adjustNegatives);
|
||||
|
||||
if (position[0] > margin[0]) {
|
||||
styles.right = (winDim[0] - position[0] + offset[0]) + 'px';
|
||||
} else {
|
||||
styles.left = (position[0] + offset[0]) + 'px';
|
||||
}
|
||||
|
||||
if (position[1] > margin[1]) {
|
||||
styles.bottom = (winDim[1] - position[1] + offset[1]) + 'px';
|
||||
} else {
|
||||
styles.top = (position[1] + offset[1]) + 'px';
|
||||
}
|
||||
|
||||
// Add the menu to the body
|
||||
body.append(element);
|
||||
|
||||
// Return a function to dismiss the bubble
|
||||
return new Popup(element, styles);
|
||||
};
|
||||
|
||||
return PopupService;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*****************************************************************************
|
||||
* 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/DateTimePickerController"],
|
||||
function (DateTimePickerController) {
|
||||
"use strict";
|
||||
|
||||
describe("The DateTimePickerController", function () {
|
||||
var mockScope,
|
||||
mockNow,
|
||||
controller;
|
||||
|
||||
function fireWatch(expr, value) {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
[ "$apply", "$watch", "$watchCollection" ]
|
||||
);
|
||||
mockScope.ngModel = {};
|
||||
mockScope.field = "testField";
|
||||
mockNow = jasmine.createSpy('now');
|
||||
controller = new DateTimePickerController(mockScope, mockNow);
|
||||
});
|
||||
|
||||
it("watches the model that was passed in", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"ngModel[field]",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,237 @@
|
||||
/*****************************************************************************
|
||||
* 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/TimeRangeController", "moment"],
|
||||
function (TimeRangeController, moment) {
|
||||
"use strict";
|
||||
|
||||
var SEC = 1000,
|
||||
MIN = 60 * SEC,
|
||||
HOUR = 60 * MIN,
|
||||
DAY = 24 * HOUR;
|
||||
|
||||
describe("The TimeRangeController", function () {
|
||||
var mockScope,
|
||||
mockNow,
|
||||
controller;
|
||||
|
||||
function fireWatch(expr, value) {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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",
|
||||
[ "$apply", "$watch", "$watchCollection" ]
|
||||
);
|
||||
mockNow = jasmine.createSpy('now');
|
||||
controller = new TimeRangeController(mockScope, mockNow);
|
||||
});
|
||||
|
||||
it("watches the model that was passed in", function () {
|
||||
expect(mockScope.$watchCollection)
|
||||
.toHaveBeenCalledWith("ngModel", jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe("when dragged", function () {
|
||||
beforeEach(function () {
|
||||
mockScope.ngModel = {
|
||||
outer: {
|
||||
start: DAY * 1000,
|
||||
end: DAY * 1001
|
||||
},
|
||||
inner: {
|
||||
start: DAY * 1000 + HOUR * 3,
|
||||
end: DAY * 1001 - HOUR * 3
|
||||
}
|
||||
};
|
||||
mockScope.spanWidth = 1000;
|
||||
fireWatch("spanWidth", mockScope.spanWidth);
|
||||
fireWatchCollection("ngModel", mockScope.ngModel);
|
||||
});
|
||||
|
||||
it("updates the start time for left drags", function () {
|
||||
mockScope.startLeftDrag();
|
||||
mockScope.leftDrag(250);
|
||||
expect(mockScope.ngModel.inner.start)
|
||||
.toEqual(DAY * 1000 + HOUR * 9);
|
||||
});
|
||||
|
||||
it("updates the end time for right drags", function () {
|
||||
mockScope.startRightDrag();
|
||||
mockScope.rightDrag(-250);
|
||||
expect(mockScope.ngModel.inner.end)
|
||||
.toEqual(DAY * 1000 + HOUR * 15);
|
||||
});
|
||||
|
||||
it("updates both start and end for middle drags", function () {
|
||||
mockScope.startMiddleDrag();
|
||||
mockScope.middleDrag(-125);
|
||||
expect(mockScope.ngModel.inner).toEqual({
|
||||
start: DAY * 1000,
|
||||
end: DAY * 1000 + HOUR * 18
|
||||
});
|
||||
mockScope.middleDrag(250);
|
||||
expect(mockScope.ngModel.inner).toEqual({
|
||||
start: DAY * 1000 + HOUR * 6,
|
||||
end: DAY * 1001
|
||||
});
|
||||
});
|
||||
|
||||
it("enforces a minimum inner span", function () {
|
||||
mockScope.startRightDrag();
|
||||
mockScope.rightDrag(-9999999);
|
||||
expect(mockScope.ngModel.inner.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.inner.start);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when outer bounds are changed", function () {
|
||||
beforeEach(function () {
|
||||
mockScope.ngModel = {
|
||||
outer: {
|
||||
start: DAY * 1000,
|
||||
end: DAY * 1001
|
||||
},
|
||||
inner: {
|
||||
start: DAY * 1000 + HOUR * 3,
|
||||
end: DAY * 1001 - HOUR * 3
|
||||
}
|
||||
};
|
||||
mockScope.spanWidth = 1000;
|
||||
fireWatch("spanWidth", mockScope.spanWidth);
|
||||
fireWatchCollection("ngModel", mockScope.ngModel);
|
||||
});
|
||||
|
||||
it("enforces a minimum outer span", function () {
|
||||
mockScope.ngModel.outer.end =
|
||||
mockScope.ngModel.outer.start - DAY * 100;
|
||||
fireWatch(
|
||||
"ngModel.outer.end",
|
||||
mockScope.ngModel.outer.end
|
||||
);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.outer.start);
|
||||
|
||||
mockScope.ngModel.outer.start =
|
||||
mockScope.ngModel.outer.end + DAY * 100;
|
||||
fireWatch(
|
||||
"ngModel.outer.start",
|
||||
mockScope.ngModel.outer.start
|
||||
);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.outer.start);
|
||||
});
|
||||
|
||||
it("enforces a minimum inner span when outer span changes", function () {
|
||||
mockScope.ngModel.outer.end =
|
||||
mockScope.ngModel.outer.start - DAY * 100;
|
||||
fireWatch(
|
||||
"ngModel.outer.end",
|
||||
mockScope.ngModel.outer.end
|
||||
);
|
||||
expect(mockScope.ngModel.inner.end)
|
||||
.toBeGreaterThan(mockScope.ngModel.inner.start);
|
||||
});
|
||||
|
||||
describe("by typing", function () {
|
||||
it("updates models", function () {
|
||||
var newStart = "1977-05-25 17:30:00",
|
||||
newEnd = "2015-12-18 03:30:00";
|
||||
|
||||
mockScope.boundsModel.start = newStart;
|
||||
fireWatch("boundsModel.start", newStart);
|
||||
expect(mockScope.ngModel.outer.start)
|
||||
.toEqual(moment.utc(newStart).valueOf());
|
||||
expect(mockScope.boundsModel.startValid)
|
||||
.toBeTruthy();
|
||||
|
||||
mockScope.boundsModel.end = newEnd;
|
||||
fireWatch("boundsModel.end", newEnd);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.toEqual(moment.utc(newEnd).valueOf());
|
||||
expect(mockScope.boundsModel.endValid)
|
||||
.toBeTruthy();
|
||||
});
|
||||
|
||||
it("displays error state", function () {
|
||||
var newStart = "Not a date",
|
||||
newEnd = "Definitely not a date",
|
||||
oldStart = mockScope.ngModel.outer.start,
|
||||
oldEnd = mockScope.ngModel.outer.end;
|
||||
|
||||
mockScope.boundsModel.start = newStart;
|
||||
fireWatch("boundsModel.start", newStart);
|
||||
expect(mockScope.ngModel.outer.start)
|
||||
.toEqual(oldStart);
|
||||
expect(mockScope.boundsModel.startValid)
|
||||
.toBeFalsy();
|
||||
|
||||
mockScope.boundsModel.end = newEnd;
|
||||
fireWatch("boundsModel.end", newEnd);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.toEqual(oldEnd);
|
||||
expect(mockScope.boundsModel.endValid)
|
||||
.toBeFalsy();
|
||||
});
|
||||
|
||||
it("does not modify user input", function () {
|
||||
// Don't want the controller "fixing" bad or
|
||||
// irregularly-formatted input out from under
|
||||
// the user's fingertips.
|
||||
var newStart = "Not a date",
|
||||
newEnd = "2015-3-3 01:02:04",
|
||||
oldStart = mockScope.ngModel.outer.start,
|
||||
oldEnd = mockScope.ngModel.outer.end;
|
||||
|
||||
mockScope.boundsModel.start = newStart;
|
||||
fireWatch("boundsModel.start", newStart);
|
||||
expect(mockScope.boundsModel.start)
|
||||
.toEqual(newStart);
|
||||
|
||||
mockScope.boundsModel.end = newEnd;
|
||||
fireWatch("boundsModel.end", newEnd);
|
||||
expect(mockScope.boundsModel.end)
|
||||
.toEqual(newEnd);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,84 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/directives/MCTClickElsewhere"],
|
||||
function (MCTClickElsewhere) {
|
||||
"use strict";
|
||||
|
||||
var JQLITE_METHODS = [ "on", "off", "find", "parent" ];
|
||||
|
||||
describe("The mct-click-elsewhere directive", function () {
|
||||
var mockDocument,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockBody,
|
||||
mockParentEl,
|
||||
testRect,
|
||||
mctClickElsewhere;
|
||||
|
||||
function testEvent(x, y) {
|
||||
return {
|
||||
pageX: x,
|
||||
pageY: y,
|
||||
preventDefault: jasmine.createSpy("preventDefault")
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockDocument =
|
||||
jasmine.createSpyObj("$document", JQLITE_METHODS);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", [ "$eval", "$apply", "$on" ]);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", JQLITE_METHODS);
|
||||
mockBody =
|
||||
jasmine.createSpyObj("body", JQLITE_METHODS);
|
||||
mockParentEl =
|
||||
jasmine.createSpyObj("parent", ["getBoundingClientRect"]);
|
||||
|
||||
testAttrs = {
|
||||
mctClickElsewhere: "some Angular expression"
|
||||
};
|
||||
testRect = {
|
||||
left: 20,
|
||||
top: 42,
|
||||
width: 60,
|
||||
height: 75
|
||||
};
|
||||
|
||||
mockDocument.find.andReturn(mockBody);
|
||||
|
||||
mctClickElsewhere = new MCTClickElsewhere(mockDocument);
|
||||
mctClickElsewhere.link(mockScope, mockElement, testAttrs);
|
||||
});
|
||||
|
||||
it("is valid as an attribute", function () {
|
||||
expect(mctClickElsewhere.restrict).toEqual("A");
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
136
platform/commonUI/general/test/directives/MCTPopupSpec.js
Normal file
136
platform/commonUI/general/test/directives/MCTPopupSpec.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/*****************************************************************************
|
||||
* 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,it,expect,beforeEach,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/directives/MCTPopup"],
|
||||
function (MCTPopup) {
|
||||
"use strict";
|
||||
|
||||
var JQLITE_METHODS = [ "on", "off", "find", "parent", "css", "append" ];
|
||||
|
||||
describe("The mct-popup directive", function () {
|
||||
var mockCompile,
|
||||
mockPopupService,
|
||||
mockPopup,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockBody,
|
||||
mockTransclude,
|
||||
mockParentEl,
|
||||
mockNewElement,
|
||||
testRect,
|
||||
mctPopup;
|
||||
|
||||
function testEvent(x, y) {
|
||||
return {
|
||||
pageX: x,
|
||||
pageY: y,
|
||||
preventDefault: jasmine.createSpy("preventDefault")
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockCompile =
|
||||
jasmine.createSpy("$compile");
|
||||
mockPopupService =
|
||||
jasmine.createSpyObj("popupService", ["display"]);
|
||||
mockPopup =
|
||||
jasmine.createSpyObj("popup", ["dismiss"]);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", [ "$eval", "$apply", "$on" ]);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", JQLITE_METHODS);
|
||||
mockBody =
|
||||
jasmine.createSpyObj("body", JQLITE_METHODS);
|
||||
mockTransclude =
|
||||
jasmine.createSpy("transclude");
|
||||
mockParentEl =
|
||||
jasmine.createSpyObj("parent", ["getBoundingClientRect"]);
|
||||
mockNewElement =
|
||||
jasmine.createSpyObj("newElement", JQLITE_METHODS);
|
||||
|
||||
testAttrs = {
|
||||
mctClickElsewhere: "some Angular expression"
|
||||
};
|
||||
testRect = {
|
||||
left: 20,
|
||||
top: 42,
|
||||
width: 60,
|
||||
height: 75
|
||||
};
|
||||
|
||||
mockCompile.andCallFake(function () {
|
||||
var mockFn = jasmine.createSpy();
|
||||
mockFn.andReturn(mockNewElement);
|
||||
return mockFn;
|
||||
});
|
||||
mockElement.parent.andReturn([mockParentEl]);
|
||||
mockParentEl.getBoundingClientRect.andReturn(testRect);
|
||||
mockPopupService.display.andReturn(mockPopup);
|
||||
|
||||
mctPopup = new MCTPopup(mockCompile, mockPopupService);
|
||||
|
||||
mctPopup.link(
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
null,
|
||||
mockTransclude
|
||||
);
|
||||
});
|
||||
|
||||
it("is valid as an element", function () {
|
||||
expect(mctPopup.restrict).toEqual("E");
|
||||
});
|
||||
|
||||
describe("creates an element which", function () {
|
||||
it("displays as a popup", function () {
|
||||
expect(mockPopupService.display).toHaveBeenCalledWith(
|
||||
mockNewElement,
|
||||
[ testRect.left, testRect.top ]
|
||||
);
|
||||
});
|
||||
|
||||
it("displays transcluded content", function () {
|
||||
var mockClone =
|
||||
jasmine.createSpyObj('clone', JQLITE_METHODS);
|
||||
mockTransclude.mostRecentCall.args[0](mockClone);
|
||||
expect(mockNewElement.append)
|
||||
.toHaveBeenCalledWith(mockClone);
|
||||
});
|
||||
|
||||
it("is removed when its containing scope is destroyed", function () {
|
||||
expect(mockPopup.dismiss).not.toHaveBeenCalled();
|
||||
mockScope.$on.calls.forEach(function (call) {
|
||||
if (call.args[0] === '$destroy') {
|
||||
call.args[1]();
|
||||
}
|
||||
});
|
||||
expect(mockPopup.dismiss).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
98
platform/commonUI/general/test/services/PopupServiceSpec.js
Normal file
98
platform/commonUI/general/test/services/PopupServiceSpec.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/*****************************************************************************
|
||||
* 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/services/PopupService"],
|
||||
function (PopupService) {
|
||||
'use strict';
|
||||
|
||||
describe("PopupService", function () {
|
||||
var mockDocument,
|
||||
testWindow,
|
||||
mockBody,
|
||||
mockElement,
|
||||
popupService;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDocument = jasmine.createSpyObj('$document', [ 'find' ]);
|
||||
testWindow = { innerWidth: 1000, innerHeight: 800 };
|
||||
mockBody = jasmine.createSpyObj('body', [ 'append' ]);
|
||||
mockElement = jasmine.createSpyObj('element', [
|
||||
'css',
|
||||
'remove'
|
||||
]);
|
||||
|
||||
mockDocument.find.andCallFake(function (query) {
|
||||
return query === 'body' && mockBody;
|
||||
});
|
||||
|
||||
popupService = new PopupService(mockDocument, testWindow);
|
||||
});
|
||||
|
||||
it("adds elements to the body of the document", function () {
|
||||
popupService.display(mockElement, [ 0, 0 ]);
|
||||
expect(mockBody.append).toHaveBeenCalledWith(mockElement);
|
||||
});
|
||||
|
||||
describe("when positioned in appropriate quadrants", function () {
|
||||
it("orients elements relative to the top-left", function () {
|
||||
popupService.display(mockElement, [ 25, 50 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
left: '25px',
|
||||
top: '50px'
|
||||
});
|
||||
});
|
||||
|
||||
it("orients elements relative to the top-right", function () {
|
||||
popupService.display(mockElement, [ 800, 50 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
right: '200px',
|
||||
top: '50px'
|
||||
});
|
||||
});
|
||||
|
||||
it("orients elements relative to the bottom-right", function () {
|
||||
popupService.display(mockElement, [ 800, 650 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
right: '200px',
|
||||
bottom: '150px'
|
||||
});
|
||||
});
|
||||
|
||||
it("orients elements relative to the bottom-left", function () {
|
||||
popupService.display(mockElement, [ 120, 650 ]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith({
|
||||
position: 'absolute',
|
||||
left: '120px',
|
||||
bottom: '150px'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
74
platform/commonUI/general/test/services/PopupSpec.js
Normal file
74
platform/commonUI/general/test/services/PopupSpec.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
|
||||
define(
|
||||
["../../src/services/Popup"],
|
||||
function (Popup) {
|
||||
'use strict';
|
||||
|
||||
describe("Popup", function () {
|
||||
var mockElement,
|
||||
testStyles,
|
||||
popup;
|
||||
|
||||
beforeEach(function () {
|
||||
mockElement =
|
||||
jasmine.createSpyObj('element', [ 'css', 'remove' ]);
|
||||
testStyles = { left: '12px', top: '14px' };
|
||||
popup = new Popup(mockElement, testStyles);
|
||||
});
|
||||
|
||||
it("applies CSS styles when instantiated", function () {
|
||||
expect(mockElement.css)
|
||||
.toHaveBeenCalledWith(testStyles);
|
||||
});
|
||||
|
||||
it("reports the orientation of the popup", function () {
|
||||
var otherStyles = {
|
||||
right: '12px',
|
||||
bottom: '14px'
|
||||
},
|
||||
otherPopup = new Popup(mockElement, otherStyles);
|
||||
|
||||
expect(popup.goesLeft()).toBeFalsy();
|
||||
expect(popup.goesRight()).toBeTruthy();
|
||||
expect(popup.goesUp()).toBeFalsy();
|
||||
expect(popup.goesDown()).toBeTruthy();
|
||||
|
||||
expect(otherPopup.goesLeft()).toBeTruthy();
|
||||
expect(otherPopup.goesRight()).toBeFalsy();
|
||||
expect(otherPopup.goesUp()).toBeTruthy();
|
||||
expect(otherPopup.goesDown()).toBeFalsy();
|
||||
});
|
||||
|
||||
it("removes elements when dismissed", function () {
|
||||
expect(mockElement.remove).not.toHaveBeenCalled();
|
||||
popup.dismiss();
|
||||
expect(mockElement.remove).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
@@ -3,16 +3,22 @@
|
||||
"controllers/BottomBarController",
|
||||
"controllers/ClickAwayController",
|
||||
"controllers/ContextMenuController",
|
||||
"controllers/DateTimePickerController",
|
||||
"controllers/GetterSetterController",
|
||||
"controllers/SelectorController",
|
||||
"controllers/SplitPaneController",
|
||||
"controllers/TimeRangeController",
|
||||
"controllers/ToggleController",
|
||||
"controllers/TreeNodeController",
|
||||
"controllers/ViewSwitcherController",
|
||||
"directives/MCTClickElsewhere",
|
||||
"directives/MCTContainer",
|
||||
"directives/MCTDrag",
|
||||
"directives/MCTPopup",
|
||||
"directives/MCTResize",
|
||||
"directives/MCTScroll",
|
||||
"services/Popup",
|
||||
"services/PopupService",
|
||||
"services/UrlService",
|
||||
"StyleSheetLoader"
|
||||
]
|
||||
|
||||
@@ -45,13 +45,12 @@
|
||||
"implementation": "services/InfoService.js",
|
||||
"depends": [
|
||||
"$compile",
|
||||
"$document",
|
||||
"$window",
|
||||
"$rootScope",
|
||||
"popupService",
|
||||
"agentService"
|
||||
]
|
||||
}
|
||||
],
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"key": "INFO_HOVER_DELAY",
|
||||
@@ -66,4 +65,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,19 @@ define({
|
||||
BUBBLE_TEMPLATE: "<mct-container key=\"bubble\" " +
|
||||
"bubble-title=\"{{bubbleTitle}}\" " +
|
||||
"bubble-layout=\"{{bubbleLayout}}\" " +
|
||||
"class=\"bubble-container\">" +
|
||||
"<mct-include key=\"bubbleTemplate\" ng-model=\"bubbleModel\">" +
|
||||
"class=\"bubble-container\">" +
|
||||
"<mct-include key=\"bubbleTemplate\" " +
|
||||
"ng-model=\"bubbleModel\">" +
|
||||
"</mct-include>" +
|
||||
"</mct-container>",
|
||||
// Pixel offset for bubble, to align arrow position
|
||||
BUBBLE_OFFSET: [ 0, -26 ],
|
||||
// Max width and margins allowed for bubbles; defined in /platform/commonUI/general/res/sass/_constants.scss
|
||||
BUBBLE_MARGIN_LR: 10,
|
||||
BUBBLE_MAX_WIDTH: 300
|
||||
// Options and classes for bubble
|
||||
BUBBLE_OPTIONS: {
|
||||
offsetX: 0,
|
||||
offsetY: -26
|
||||
},
|
||||
BUBBLE_MOBILE_POSITION: [ 0, -25 ],
|
||||
// Max width and margins allowed for bubbles;
|
||||
// defined in /platform/commonUI/general/res/sass/_constants.scss
|
||||
BUBBLE_MARGIN_LR: 10,
|
||||
BUBBLE_MAX_WIDTH: 300
|
||||
});
|
||||
|
||||
@@ -27,18 +27,18 @@ define(
|
||||
"use strict";
|
||||
|
||||
var BUBBLE_TEMPLATE = InfoConstants.BUBBLE_TEMPLATE,
|
||||
OFFSET = InfoConstants.BUBBLE_OFFSET;
|
||||
MOBILE_POSITION = InfoConstants.BUBBLE_MOBILE_POSITION,
|
||||
OPTIONS = InfoConstants.BUBBLE_OPTIONS;
|
||||
|
||||
/**
|
||||
* Displays informative content ("info bubbles") for the user.
|
||||
* @memberof platform/commonUI/inspect
|
||||
* @constructor
|
||||
*/
|
||||
function InfoService($compile, $document, $window, $rootScope, agentService) {
|
||||
function InfoService($compile, $rootScope, popupService, agentService) {
|
||||
this.$compile = $compile;
|
||||
this.$document = $document;
|
||||
this.$window = $window;
|
||||
this.$rootScope = $rootScope;
|
||||
this.popupService = popupService;
|
||||
this.agentService = agentService;
|
||||
}
|
||||
|
||||
@@ -55,53 +55,47 @@ define(
|
||||
*/
|
||||
InfoService.prototype.display = function (templateKey, title, content, position) {
|
||||
var $compile = this.$compile,
|
||||
$document = this.$document,
|
||||
$window = this.$window,
|
||||
$rootScope = this.$rootScope,
|
||||
body = $document.find('body'),
|
||||
scope = $rootScope.$new(),
|
||||
winDim = [$window.innerWidth, $window.innerHeight],
|
||||
bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR + InfoConstants.BUBBLE_MAX_WIDTH,
|
||||
goLeft = position[0] > (winDim[0] - bubbleSpaceLR),
|
||||
goUp = position[1] > (winDim[1] / 2),
|
||||
span = $compile('<span></span>')(scope),
|
||||
bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR +
|
||||
InfoConstants.BUBBLE_MAX_WIDTH,
|
||||
options,
|
||||
popup,
|
||||
bubble;
|
||||
|
||||
|
||||
options = Object.create(OPTIONS);
|
||||
options.marginX = -bubbleSpaceLR;
|
||||
|
||||
// On a phone, bubble takes up more screen real estate,
|
||||
// so position it differently (toward the bottom)
|
||||
if (this.agentService.isPhone(navigator.userAgent)) {
|
||||
position = MOBILE_POSITION;
|
||||
options = {};
|
||||
}
|
||||
|
||||
popup = this.popupService.display(span, position, options);
|
||||
|
||||
// Pass model & container parameters into the scope
|
||||
scope.bubbleModel = content;
|
||||
scope.bubbleTemplate = templateKey;
|
||||
scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' +
|
||||
(goLeft ? 'arw-right' : 'arw-left');
|
||||
scope.bubbleTitle = title;
|
||||
// Style the bubble according to how it was positioned
|
||||
scope.bubbleLayout = [
|
||||
popup.goesUp() ? 'arw-btm' : 'arw-top',
|
||||
popup.goesLeft() ? 'arw-right' : 'arw-left'
|
||||
].join(' ');
|
||||
scope.bubbleLayout = 'arw-top arw-left';
|
||||
|
||||
// Create the context menu
|
||||
// Create the info bubble, now that we know how to
|
||||
// point the arrow...
|
||||
bubble = $compile(BUBBLE_TEMPLATE)(scope);
|
||||
span.append(bubble);
|
||||
|
||||
// Position the bubble
|
||||
bubble.css('position', 'absolute');
|
||||
if (this.agentService.isPhone(navigator.userAgent)) {
|
||||
bubble.css('right', '0px');
|
||||
bubble.css('left', '0px');
|
||||
bubble.css('top', 'auto');
|
||||
bubble.css('bottom', '25px');
|
||||
} else {
|
||||
if (goLeft) {
|
||||
bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
|
||||
} else {
|
||||
bubble.css('left', position[0] + OFFSET[0] + 'px');
|
||||
}
|
||||
if (goUp) {
|
||||
bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
|
||||
} else {
|
||||
bubble.css('top', position[1] + OFFSET[1] + 'px');
|
||||
}
|
||||
}
|
||||
|
||||
// Add the menu to the body
|
||||
body.append(bubble);
|
||||
|
||||
// Return a function to dismiss the bubble
|
||||
return function () {
|
||||
bubble.remove();
|
||||
// Return a function to dismiss the info bubble
|
||||
return function dismiss() {
|
||||
popup.dismiss();
|
||||
scope.$destroy();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -28,117 +28,85 @@ define(
|
||||
|
||||
describe("The info service", function () {
|
||||
var mockCompile,
|
||||
mockDocument,
|
||||
testWindow,
|
||||
mockRootScope,
|
||||
mockPopupService,
|
||||
mockAgentService,
|
||||
mockCompiledTemplate,
|
||||
testScope,
|
||||
mockBody,
|
||||
mockElement,
|
||||
mockScope,
|
||||
mockElements,
|
||||
mockPopup,
|
||||
service;
|
||||
|
||||
beforeEach(function () {
|
||||
mockCompile = jasmine.createSpy('$compile');
|
||||
mockDocument = jasmine.createSpyObj('$document', ['find']);
|
||||
testWindow = { innerWidth: 1000, innerHeight: 100 };
|
||||
mockRootScope = jasmine.createSpyObj('$rootScope', ['$new']);
|
||||
mockAgentService = jasmine.createSpyObj('agentService', ['isMobile', 'isPhone']);
|
||||
mockCompiledTemplate = jasmine.createSpy('template');
|
||||
testScope = {};
|
||||
mockBody = jasmine.createSpyObj('body', ['append']);
|
||||
mockElement = jasmine.createSpyObj('element', ['css', 'remove']);
|
||||
mockPopupService = jasmine.createSpyObj(
|
||||
'popupService',
|
||||
['display']
|
||||
);
|
||||
mockPopup = jasmine.createSpyObj('popup', [
|
||||
'dismiss',
|
||||
'goesLeft',
|
||||
'goesRight',
|
||||
'goesUp',
|
||||
'goesDown'
|
||||
]);
|
||||
|
||||
mockDocument.find.andCallFake(function (tag) {
|
||||
return tag === 'body' ? mockBody : undefined;
|
||||
mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
|
||||
mockElements = [];
|
||||
|
||||
mockPopupService.display.andReturn(mockPopup);
|
||||
mockCompile.andCallFake(function () {
|
||||
var mockCompiledTemplate = jasmine.createSpy('template'),
|
||||
mockElement = jasmine.createSpyObj('element', [
|
||||
'css',
|
||||
'remove',
|
||||
'append'
|
||||
]);
|
||||
mockCompiledTemplate.andReturn(mockElement);
|
||||
mockElements.push(mockElement);
|
||||
return mockCompiledTemplate;
|
||||
});
|
||||
mockCompile.andReturn(mockCompiledTemplate);
|
||||
mockCompiledTemplate.andReturn(mockElement);
|
||||
mockRootScope.$new.andReturn(testScope);
|
||||
mockRootScope.$new.andReturn(mockScope);
|
||||
|
||||
service = new InfoService(
|
||||
mockCompile,
|
||||
mockDocument,
|
||||
testWindow,
|
||||
mockRootScope,
|
||||
mockPopupService,
|
||||
mockAgentService
|
||||
);
|
||||
});
|
||||
|
||||
it("creates elements and appends them to the body to display", function () {
|
||||
service.display('', '', {}, [0, 0]);
|
||||
expect(mockBody.append).toHaveBeenCalledWith(mockElement);
|
||||
it("creates elements and displays them as popups", function () {
|
||||
service.display('', '', {}, [123, 456]);
|
||||
expect(mockPopupService.display).toHaveBeenCalledWith(
|
||||
mockElements[0],
|
||||
[ 123, 456 ],
|
||||
jasmine.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
it("provides a function to remove displayed info bubbles", function () {
|
||||
var fn = service.display('', '', {}, [0, 0]);
|
||||
expect(mockElement.remove).not.toHaveBeenCalled();
|
||||
expect(mockPopup.dismiss).not.toHaveBeenCalled();
|
||||
fn();
|
||||
expect(mockElement.remove).toHaveBeenCalled();
|
||||
expect(mockPopup.dismiss).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("depending on mouse position", function () {
|
||||
// Positioning should vary based on quadrant in window,
|
||||
// which is 1000 x 100 in this test case.
|
||||
it("displays from the top-left in the top-left quadrant", function () {
|
||||
service.display('', '', {}, [250, 25]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'left',
|
||||
(250 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
|
||||
);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'top',
|
||||
(25 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
|
||||
);
|
||||
});
|
||||
|
||||
it("displays from the top-right in the top-right quadrant", function () {
|
||||
service.display('', '', {}, [700, 25]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'right',
|
||||
(300 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
|
||||
);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'top',
|
||||
(25 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
|
||||
);
|
||||
});
|
||||
|
||||
it("displays from the bottom-left in the bottom-left quadrant", function () {
|
||||
service.display('', '', {}, [250, 70]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'left',
|
||||
(250 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
|
||||
);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'bottom',
|
||||
(30 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
|
||||
);
|
||||
});
|
||||
|
||||
it("displays from the bottom-right in the bottom-right quadrant", function () {
|
||||
service.display('', '', {}, [800, 60]);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'right',
|
||||
(200 + InfoConstants.BUBBLE_OFFSET[0]) + 'px'
|
||||
);
|
||||
expect(mockElement.css).toHaveBeenCalledWith(
|
||||
'bottom',
|
||||
(40 + InfoConstants.BUBBLE_OFFSET[1]) + 'px'
|
||||
);
|
||||
});
|
||||
|
||||
it("when on phone device, positioning is always on bottom", function () {
|
||||
mockAgentService.isPhone.andReturn(true);
|
||||
service = new InfoService(
|
||||
mockCompile,
|
||||
mockDocument,
|
||||
testWindow,
|
||||
mockRootScope,
|
||||
mockAgentService
|
||||
);
|
||||
service.display('', '', {}, [0, 0]);
|
||||
});
|
||||
it("when on phone device, positions at bottom", function () {
|
||||
mockAgentService.isPhone.andReturn(true);
|
||||
service = new InfoService(
|
||||
mockCompile,
|
||||
mockRootScope,
|
||||
mockPopupService,
|
||||
mockAgentService
|
||||
);
|
||||
service.display('', '', {}, [123, 456]);
|
||||
expect(mockPopupService.display).toHaveBeenCalledWith(
|
||||
mockElements[0],
|
||||
[ 0, -25 ],
|
||||
jasmine.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,14 @@ $colorKey: #0099cc;
|
||||
$colorKeySelectedBg: #005177;
|
||||
$colorKeyFg: #fff;
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.1);
|
||||
$colorA: #ccc;
|
||||
$colorAHov: #fff;
|
||||
$contrastRatioPercent: 7%;
|
||||
$basicCr: 3px;
|
||||
$controlCr: 3px;
|
||||
$smallCr: 2px;
|
||||
|
||||
// Buttons
|
||||
// Buttons and Controls
|
||||
$colorBtnBg: pullForward($colorBodyBg, $contrastRatioPercent); //
|
||||
$colorBtnFg: $colorBodyFg;
|
||||
$colorBtnMajorBg: $colorKey;
|
||||
@@ -20,6 +22,18 @@ $colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnIcon: $colorKey;
|
||||
$colorInvokeMenu: #fff;
|
||||
$contrastInvokeMenuPercent: 20%;
|
||||
$shdwBtns: rgba(black, 0.2) 0 1px 2px;
|
||||
$sliderColorBase: $colorKey;
|
||||
$sliderColorRangeHolder: rgba(black, 0.1);
|
||||
$sliderColorRange: rgba($sliderColorBase, 0.3);
|
||||
$sliderColorRangeHov: rgba($sliderColorBase, 0.5);
|
||||
$sliderColorKnob: rgba($sliderColorBase, 0.6);
|
||||
$sliderColorKnobHov: $sliderColorBase;
|
||||
$sliderColorRangeValHovBg: rgba($sliderColorBase, 0.1);
|
||||
$sliderColorRangeValHovFg: $colorKeyFg;
|
||||
$sliderKnobW: nth($ueTimeControlH,2)/2;
|
||||
$timeControllerToiLineColor: #00c2ff;
|
||||
$timeControllerToiLineColorHov: #fff;
|
||||
|
||||
// General Colors
|
||||
$colorAlt1: #ffc700;
|
||||
@@ -32,6 +46,7 @@ $colorGridLines: rgba(#fff, 0.05);
|
||||
$colorInvokeMenu: #fff;
|
||||
$colorObjHdrTxt: $colorBodyFg;
|
||||
$colorObjHdrIc: pullForward($colorObjHdrTxt, 20%);
|
||||
$colorTick: rgba(white, 0.2);
|
||||
|
||||
// Menu colors
|
||||
$colorMenuBg: pullForward($colorBodyBg, 23%);
|
||||
@@ -111,16 +126,17 @@ $colorItemBgSelected: $colorKey;
|
||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
||||
$colorTabBodyBg: darken($colorBodyBg, 10%);
|
||||
$colorTabBodyFg: lighten($colorTabBodyBg, 40%);
|
||||
$colorTabHeaderBg: lighten($colorBodyBg, 10%);
|
||||
$colorTabHeaderFg: lighten($colorTabHeaderBg, 40%);
|
||||
$colorTabHeaderBg: rgba(white, 0.1); // lighten($colorBodyBg, 10%);
|
||||
$colorTabHeaderFg: $colorBodyFg; //lighten($colorTabHeaderBg, 40%);
|
||||
$colorTabHeaderBorder: $colorBodyBg;
|
||||
|
||||
// Plot
|
||||
$colorPlotBg: rgba(black, 0.1);
|
||||
$colorPlotFg: $colorBodyFg;
|
||||
$colorPlotHash: rgba(white, 0.2);
|
||||
$colorPlotHash: $colorTick;
|
||||
$stylePlotHash: dashed;
|
||||
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
|
||||
|
||||
// Tree
|
||||
$colorItemTreeIcon: $colorKey;
|
||||
@@ -151,5 +167,16 @@ $colorGrippyInteriorHover: $colorKey;
|
||||
// Mobile
|
||||
$colorMobilePaneLeft: darken($colorBodyBg, 5%);
|
||||
|
||||
// Datetime Picker
|
||||
$colorCalCellHovBg: $colorKey;
|
||||
$colorCalCellHovFg: $colorKeyFg;
|
||||
$colorCalCellSelectedBg: $colorItemTreeSelectedBg;
|
||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
|
||||
$colorCalCellInMonthBg: pushBack($colorMenuBg, 5%);
|
||||
|
||||
// About Screen
|
||||
$colorAboutLink: #84b3ff;
|
||||
$colorAboutLink: #84b3ff;
|
||||
|
||||
// Loading
|
||||
$colorLoadingBg: rgba($colorBodyFg, 0.2);
|
||||
$colorLoadingFg: $colorAlt1;
|
||||
@@ -1,13 +1,13 @@
|
||||
@mixin containerSubtle($bg: $colorBodyBg, $fg: $colorBodyFg, $hover: false) {
|
||||
@include containerBase($bg, $fg);
|
||||
@include background-image(linear-gradient(lighten($bg, 5%), $bg));
|
||||
@include boxShdwSubtle();
|
||||
@include boxShdw($shdwBtns);
|
||||
}
|
||||
|
||||
@mixin btnSubtle($bg: $colorBodyBg, $bgHov: none, $fg: $colorBodyFg, $ic: $colorBtnIcon) {
|
||||
@mixin btnSubtle($bg: $colorBodyBg, $bgHov: none, $fg: $colorBodyFg, $ic: $colorBtnIcon) {
|
||||
@include containerSubtle($bg, $fg);
|
||||
@include btnBase($bg, linear-gradient(lighten($bg, 15%), lighten($bg, 10%)), $fg, $ic);
|
||||
@include text-shadow(rgba(black, 0.3) 0 1px 1px);
|
||||
@include text-shadow($shdwItemText);
|
||||
}
|
||||
|
||||
@function pullForward($c: $colorBodyBg, $p: 20%) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,14 @@ $colorKey: #0099cc;
|
||||
$colorKeySelectedBg: $colorKey;
|
||||
$colorKeyFg: #fff;
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||
$colorA: #999;
|
||||
$colorAHov: $colorKey;
|
||||
$contrastRatioPercent: 40%;
|
||||
$basicCr: 4px;
|
||||
$controlCr: $basicCr;
|
||||
$smallCr: 3px;
|
||||
|
||||
// Buttons
|
||||
// Buttons and Controls
|
||||
$colorBtnBg: pullForward($colorBodyBg, $contrastRatioPercent);
|
||||
$colorBtnFg: #fff;
|
||||
$colorBtnMajorBg: $colorKey;
|
||||
@@ -20,10 +22,22 @@ $colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnIcon: #eee;
|
||||
$colorInvokeMenu: #000;
|
||||
$contrastInvokeMenuPercent: 40%;
|
||||
$shdwBtns: none;
|
||||
$sliderColorBase: $colorKey;
|
||||
$sliderColorRangeHolder: rgba(black, 0.07);
|
||||
$sliderColorRange: rgba($sliderColorBase, 0.2);
|
||||
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
|
||||
$sliderColorKnob: rgba($sliderColorBase, 0.5);
|
||||
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
|
||||
$sliderColorRangeValHovBg: $sliderColorRange; //rgba($sliderColorBase, 0.1);
|
||||
$sliderColorRangeValHovFg: $colorBodyFg;
|
||||
$sliderKnobW: nth($ueTimeControlH,2)/2;
|
||||
$timeControllerToiLineColor: $colorBodyFg;
|
||||
$timeControllerToiLineColorHov: #0052b5;
|
||||
|
||||
// General Colors
|
||||
$colorAlt1: #ff6600;
|
||||
$colorAlert: #ff533a;
|
||||
$colorAlt1: #776ba2;
|
||||
$colorAlert: #ff3c00;
|
||||
$colorIconLink: #49dedb;
|
||||
$colorPausedBg: #ff9900;
|
||||
$colorPausedFg: #fff;
|
||||
@@ -32,6 +46,7 @@ $colorGridLines: rgba(#000, 0.05);
|
||||
$colorInvokeMenu: #fff;
|
||||
$colorObjHdrTxt: $colorBodyFg;
|
||||
$colorObjHdrIc: pushBack($colorObjHdrTxt, 30%);
|
||||
$colorTick: rgba(black, 0.2);
|
||||
|
||||
// Menu colors
|
||||
$colorMenuBg: pushBack($colorBodyBg, 10%);
|
||||
@@ -57,20 +72,6 @@ $colorInputBg: $colorGenBg;
|
||||
$colorInputFg: $colorBodyFg;
|
||||
$colorFormText: pushBack($colorBodyFg, 10%);
|
||||
$colorInputIcon: pushBack($colorBodyFg, 25%);
|
||||
|
||||
// Status colors, mainly used for messaging and item ancillary symbols
|
||||
$colorStatusFg: #fff;
|
||||
$colorStatusDefault: #ccc;
|
||||
$colorStatusInfo: #60ba7b;
|
||||
$colorStatusAlert: #ffb66c;
|
||||
$colorStatusError: #c96b68;
|
||||
$colorProgressBarOuter: rgba(#000, 0.1);
|
||||
$colorProgressBarAmt: #0a0;
|
||||
$progressBarHOverlay: 15px;
|
||||
$progressBarStripeW: 20px;
|
||||
$shdwStatusIc: rgba(white, 0.8) 0 0px 5px;
|
||||
|
||||
// Selects
|
||||
$colorSelectBg: #ddd;
|
||||
$colorSelectFg: $colorBodyFg;
|
||||
|
||||
@@ -118,9 +119,10 @@ $colorTabHeaderBorder: $colorBodyBg;
|
||||
// Plot
|
||||
$colorPlotBg: rgba(black, 0.05);
|
||||
$colorPlotFg: $colorBodyFg;
|
||||
$colorPlotHash: rgba(black, 0.2);
|
||||
$colorPlotHash: $colorTick;
|
||||
$stylePlotHash: dashed;
|
||||
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
|
||||
|
||||
// Tree
|
||||
$colorItemTreeIcon: $colorKey;
|
||||
@@ -151,5 +153,16 @@ $colorGrippyInteriorHover: $colorBodyBg;
|
||||
// Mobile
|
||||
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
|
||||
|
||||
// Datetime Picker, Calendar
|
||||
$colorCalCellHovBg: $colorKey;
|
||||
$colorCalCellHovFg: $colorKeyFg;
|
||||
$colorCalCellSelectedBg: $colorItemTreeSelectedBg;
|
||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
|
||||
$colorCalCellInMonthBg: pullForward($colorMenuBg, 5%);
|
||||
|
||||
// About Screen
|
||||
$colorAboutLink: #84b3ff;
|
||||
$colorAboutLink: #84b3ff;
|
||||
|
||||
// Loading
|
||||
$colorLoadingFg: $colorAlt1;
|
||||
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
||||
@@ -1,5 +1,6 @@
|
||||
@mixin containerSubtle($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||
@include containerBase($bg, $fg);
|
||||
@include boxShdw($shdwBtns);
|
||||
}
|
||||
|
||||
@mixin btnSubtle($bg: $colorBtnBg, $bgHov: none, $fg: $colorBtnFg, $ic: $colorBtnIcon) {
|
||||
|
||||
Reference in New Issue
Block a user