mirror of
https://github.com/nasa/openmct.git
synced 2025-06-19 15:43:48 +00:00
Merge pull request #830 from nasa/time-conductor-ux
Time Conductor updates query on blur, mobile support
This commit is contained in:
@ -1,54 +1,42 @@
|
|||||||
@mixin toiLineHovEffects() {
|
@mixin toiLineHovEffects() {
|
||||||
//@include pulse(.25s);
|
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
background-color: $timeControllerToiLineColorHov;
|
background-color: $timeControllerToiLineColorHov;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mct-include.l-time-controller {
|
.l-time-controller {
|
||||||
$minW: 500px;
|
$minW: 500px;
|
||||||
$knobHOffset: 0px;
|
$knobHOffset: 0px;
|
||||||
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
||||||
$rangeValPad: $interiorMargin;
|
$rangeValPad: $interiorMargin;
|
||||||
$rangeValOffset: $sliderKnobW;
|
$rangeValOffset: $sliderKnobW;
|
||||||
//$knobCr: $sliderKnobW;
|
|
||||||
$timeRangeSliderLROffset: 130px + $sliderKnobW + $rangeValOffset;
|
$timeRangeSliderLROffset: 130px + $sliderKnobW + $rangeValOffset;
|
||||||
$r1H: nth($ueTimeControlH,1);
|
$r1H: nth($ueTimeControlH,1);
|
||||||
$r2H: nth($ueTimeControlH,2);
|
$r2H: nth($ueTimeControlH,2);
|
||||||
$r3H: nth($ueTimeControlH,3);
|
$r3H: nth($ueTimeControlH,3);
|
||||||
|
|
||||||
//@include absPosDefault();
|
|
||||||
//@include test();
|
|
||||||
display: block;
|
display: block;
|
||||||
//top: auto;
|
|
||||||
height: $r1H + $r2H + $r3H + ($interiorMargin * 2);
|
height: $r1H + $r2H + $r3H + ($interiorMargin * 2);
|
||||||
min-width: $minW;
|
min-width: $minW;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
|
||||||
.l-time-range-inputs-holder,
|
|
||||||
.l-time-range-slider {
|
|
||||||
//font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-time-range-inputs-holder,
|
.l-time-range-inputs-holder,
|
||||||
.l-time-range-slider-holder,
|
.l-time-range-slider-holder,
|
||||||
.l-time-range-ticks-holder
|
.l-time-range-ticks-holder
|
||||||
{
|
{
|
||||||
//@include test();
|
|
||||||
@include absPosDefault(0, visible);
|
@include absPosDefault(0, visible);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
top: auto;
|
top: auto;
|
||||||
}
|
}
|
||||||
.l-time-range-slider,
|
.l-time-range-slider,
|
||||||
.l-time-range-ticks {
|
.l-time-range-ticks {
|
||||||
//@include test(red, 0.1);
|
|
||||||
@include absPosDefault(0, visible);
|
@include absPosDefault(0, visible);
|
||||||
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.l-time-range-inputs-holder {
|
.l-time-range-inputs-holder {
|
||||||
//@include test(red);
|
|
||||||
height: $r1H; bottom: $r2H + $r3H + ($interiorMarginSm * 2);
|
height: $r1H; bottom: $r2H + $r3H + ($interiorMarginSm * 2);
|
||||||
padding-top: $interiorMargin;
|
padding-top: $interiorMargin;
|
||||||
border-top: 1px solid $colorInteriorBorder;
|
border-top: 1px solid $colorInteriorBorder;
|
||||||
@ -70,7 +58,6 @@ mct-include.l-time-controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.l-time-range-slider-holder {
|
.l-time-range-slider-holder {
|
||||||
//@include test(green);
|
|
||||||
height: $r2H; bottom: $r3H + ($interiorMarginSm * 1);
|
height: $r2H; bottom: $r3H + ($interiorMarginSm * 1);
|
||||||
.range-holder {
|
.range-holder {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -82,7 +69,6 @@ mct-include.l-time-controller {
|
|||||||
$myW: 8px;
|
$myW: 8px;
|
||||||
@include transform(translateX(50%));
|
@include transform(translateX(50%));
|
||||||
position: absolute;
|
position: absolute;
|
||||||
//@include test();
|
|
||||||
top: 0; right: 0; bottom: 0px; left: auto;
|
top: 0; right: 0; bottom: 0px; left: auto;
|
||||||
width: $myW;
|
width: $myW;
|
||||||
height: auto;
|
height: auto;
|
||||||
@ -97,7 +83,6 @@ mct-include.l-time-controller {
|
|||||||
// Vert line
|
// Vert line
|
||||||
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
||||||
width: 2px;
|
width: 2px;
|
||||||
//top: 0; right: 3px; bottom: 0; left: 3px;
|
|
||||||
}
|
}
|
||||||
&:after {
|
&:after {
|
||||||
// Circle element
|
// Circle element
|
||||||
@ -114,7 +99,6 @@ mct-include.l-time-controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:not(:active) {
|
&:not(:active) {
|
||||||
//@include test(#ff00cc);
|
|
||||||
.knob,
|
.knob,
|
||||||
.range {
|
.range {
|
||||||
@include transition-property(left, right);
|
@include transition-property(left, right);
|
||||||
@ -155,7 +139,6 @@ mct-include.l-time-controller {
|
|||||||
.knob {
|
.knob {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
.range-value {
|
.range-value {
|
||||||
//@include test($sliderColorRange);
|
|
||||||
@include trans-prop-nice-fade(.25s);
|
@include trans-prop-nice-fade(.25s);
|
||||||
padding: 0 $rangeValOffset;
|
padding: 0 $rangeValOffset;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -167,7 +150,6 @@ mct-include.l-time-controller {
|
|||||||
color: $sliderColorKnobHov;
|
color: $sliderColorKnobHov;
|
||||||
}
|
}
|
||||||
&.knob-l {
|
&.knob-l {
|
||||||
//border-bottom-left-radius: $knobCr; // MOVED TO _CONTROLS.SCSS
|
|
||||||
margin-left: $knobM;
|
margin-left: $knobM;
|
||||||
.range-value {
|
.range-value {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
@ -175,7 +157,6 @@ mct-include.l-time-controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.knob-r {
|
&.knob-r {
|
||||||
//border-bottom-right-radius: $knobCr;
|
|
||||||
margin-right: $knobM;
|
margin-right: $knobM;
|
||||||
.range-value {
|
.range-value {
|
||||||
left: $rangeValOffset;
|
left: $rangeValOffset;
|
||||||
@ -185,15 +166,189 @@ mct-include.l-time-controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.l-time-domain-selector {
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//.slot.range-holder {
|
|
||||||
// background-color: $sliderColorRangeHolder;
|
|
||||||
//}
|
|
||||||
|
|
||||||
.s-time-range-val {
|
.s-time-range-val {
|
||||||
//@include test();
|
|
||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
background-color: $colorInputBg;
|
background-color: $colorInputBg;
|
||||||
padding: 1px 1px 0 $interiorMargin;
|
padding: 1px 1px 0 $interiorMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include phoneandtablet {
|
||||||
|
.l-time-controller, .l-time-range-inputs-holder {
|
||||||
|
min-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-controller {
|
||||||
|
|
||||||
|
.l-time-domain-selector {
|
||||||
|
select {
|
||||||
|
height: 25px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-slider-holder, .l-time-range-ticks-holder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-range-start, .time-range-end, {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
.l-time-range-input {
|
||||||
|
display: block;
|
||||||
|
.s-btn {
|
||||||
|
padding-right: 18px;
|
||||||
|
white-space: nowrap;
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include phone {
|
||||||
|
.l-time-controller {
|
||||||
|
height: 48px;
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-domain-selector {
|
||||||
|
width: 33%;
|
||||||
|
bottom: -9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
.l-time-range-input {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
.s-btn {
|
||||||
|
width: 66%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
&.ui-symbol {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.lbl {
|
||||||
|
width: 33%;
|
||||||
|
right: 0px;
|
||||||
|
top: 5px;
|
||||||
|
display: block;
|
||||||
|
height: 25px;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 25px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include tablet {
|
||||||
|
.l-time-controller {
|
||||||
|
height: 17px;
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
bottom: -7px;
|
||||||
|
left: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-domain-selector {
|
||||||
|
width: 23%;
|
||||||
|
right: -4px;
|
||||||
|
bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
.l-time-range-input {
|
||||||
|
float: left;
|
||||||
|
.s-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include tabletLandscape {
|
||||||
|
.l-time-controller {
|
||||||
|
height: 17px;
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
bottom: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-domain-selector {
|
||||||
|
width: 23%;
|
||||||
|
right: auto;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 391px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
&.ui-symbol, &.lbl {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-tree-hidden .l-time-controller {
|
||||||
|
.l-time-domain-selector {
|
||||||
|
left: 667px;
|
||||||
|
}
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
padding-left: 277px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include tabletPortrait {
|
||||||
|
.l-time-controller {
|
||||||
|
height: 17px;
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
bottom: -7px;
|
||||||
|
left: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-domain-selector {
|
||||||
|
width: 23%;
|
||||||
|
right: -4px;
|
||||||
|
bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
.l-time-range-input {
|
||||||
|
width: 38%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
&.ui-symbol, &.lbl {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,15 +19,18 @@
|
|||||||
this source code distribution or the Licensing information page available
|
this source code distribution or the Licensing information page available
|
||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<div ng-controller="TimeRangeController">
|
<div ng-controller="TimeRangeController as trCtrl">
|
||||||
<form class="l-time-range-inputs-holder"
|
<form class="l-time-range-inputs-holder"
|
||||||
ng-submit="updateBoundsFromForm()">
|
ng-submit="trCtrl.updateBoundsFromForm()">
|
||||||
<span class="l-time-range-inputs-elem ui-symbol type-icon">C</span>
|
<span class="l-time-range-inputs-elem ui-symbol type-icon">C</span>
|
||||||
<span class="l-time-range-input">
|
<span class="l-time-range-input">
|
||||||
<mct-control key="'datetime-field'"
|
<mct-control key="'datetime-field'"
|
||||||
structure="{ format: parameters.format, validate: validateStart }"
|
structure="{
|
||||||
|
format: parameters.format,
|
||||||
|
validate: trCtrl.validateStart
|
||||||
|
}"
|
||||||
ng-model="formModel"
|
ng-model="formModel"
|
||||||
ng-blur="updateBoundsFromForm()"
|
ng-blur="trCtrl.updateBoundsFromForm()"
|
||||||
field="'start'"
|
field="'start'"
|
||||||
class="time-range-start">
|
class="time-range-start">
|
||||||
</mct-control>
|
</mct-control>
|
||||||
@ -37,9 +40,12 @@
|
|||||||
|
|
||||||
<span class="l-time-range-input" ng-controller="ToggleController as t2">
|
<span class="l-time-range-input" ng-controller="ToggleController as t2">
|
||||||
<mct-control key="'datetime-field'"
|
<mct-control key="'datetime-field'"
|
||||||
structure="{ format: parameters.format, validate: validateEnd }"
|
structure="{
|
||||||
|
format: parameters.format,
|
||||||
|
validate: trCtrl.validateEnd
|
||||||
|
}"
|
||||||
ng-model="formModel"
|
ng-model="formModel"
|
||||||
ng-blur="updateBoundsFromForm()"
|
ng-blur="trCtrl.updateBoundsFromForm()"
|
||||||
field="'end'"
|
field="'end'"
|
||||||
class="time-range-end">
|
class="time-range-end">
|
||||||
</mct-control>
|
</mct-control>
|
||||||
@ -53,22 +59,25 @@
|
|||||||
<div class="slider"
|
<div class="slider"
|
||||||
mct-resize="spanWidth = bounds.width">
|
mct-resize="spanWidth = bounds.width">
|
||||||
<div class="knob knob-l"
|
<div class="knob knob-l"
|
||||||
mct-drag-down="startLeftDrag()"
|
mct-drag-down="trCtrl.startLeftDrag()"
|
||||||
mct-drag="leftDrag(delta[0])"
|
mct-drag="trCtrl.leftDrag(delta[0])"
|
||||||
ng-style="{ left: startInnerPct }">
|
ng-style="{ left: startInnerPct }">
|
||||||
<div class="range-value">{{startInnerText}}</div>
|
<div class="range-value">{{startInnerText}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="knob knob-r"
|
<div class="knob knob-r"
|
||||||
mct-drag-down="startRightDrag()"
|
mct-drag-down="trCtrl.startRightDrag()"
|
||||||
mct-drag="rightDrag(delta[0])"
|
mct-drag="trCtrl.rightDrag(delta[0])"
|
||||||
ng-style="{ right: endInnerPct }">
|
ng-style="{ right: endInnerPct }">
|
||||||
<div class="range-value">{{endInnerText}}</div>
|
<div class="range-value">{{endInnerText}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="slot range-holder">
|
<div class="slot range-holder">
|
||||||
<div class="range"
|
<div class="range"
|
||||||
mct-drag-down="startMiddleDrag()"
|
mct-drag-down="trCtrl.startMiddleDrag()"
|
||||||
mct-drag="middleDrag(delta[0])"
|
mct-drag="trCtrl.middleDrag(delta[0])"
|
||||||
ng-style="{ left: startInnerPct, right: endInnerPct}">
|
ng-style="{
|
||||||
|
left: startInnerPct,
|
||||||
|
right: endInnerPct
|
||||||
|
}">
|
||||||
<div class="toi-line"></div>
|
<div class="toi-line"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,247 +19,289 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define,Promise*/
|
/*global define*/
|
||||||
|
|
||||||
define(
|
define([
|
||||||
['moment'],
|
|
||||||
function (moment) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var TICK_SPACING_PX = 150;
|
], function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var TICK_SPACING_PX = 150;
|
||||||
|
|
||||||
/**
|
/* format number as percent; 0.0-1.0 to "0%"-"100%" */
|
||||||
* Controller used by the `time-controller` template.
|
function toPercent(p) {
|
||||||
* @memberof platform/commonUI/general
|
return (100 * p) + "%";
|
||||||
* @constructor
|
|
||||||
* @param $scope the Angular scope for this controller
|
|
||||||
* @param {FormatService} formatService the service to user to format
|
|
||||||
* domain values
|
|
||||||
* @param {string} defaultFormat the format to request when no
|
|
||||||
* format has been otherwise specified
|
|
||||||
* @param {Function} now a function to return current system time
|
|
||||||
*/
|
|
||||||
function TimeRangeController($scope, formatService, defaultFormat, now) {
|
|
||||||
var tickCount = 2,
|
|
||||||
innerMinimumSpan = 1000, // 1 second
|
|
||||||
outerMinimumSpan = 1000, // 1 second
|
|
||||||
initialDragValue,
|
|
||||||
formatter = formatService.getFormat(defaultFormat);
|
|
||||||
|
|
||||||
function formatTimestamp(ts) {
|
|
||||||
return formatter.format(ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// From 0.0-1.0 to "0%"-"100%"
|
|
||||||
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 updateViewFromModel(ngModel) {
|
|
||||||
ngModel = ngModel || {};
|
|
||||||
ngModel.outer = ngModel.outer || defaultBounds();
|
|
||||||
ngModel.inner = ngModel.inner || copyBounds(ngModel.outer);
|
|
||||||
|
|
||||||
// Stick it back is scope (in case we just set defaults)
|
|
||||||
$scope.ngModel = ngModel;
|
|
||||||
|
|
||||||
updateViewForInnerSpanFromModel(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 updateFormModel() {
|
|
||||||
$scope.formModel = {
|
|
||||||
start: (($scope.ngModel || {}).outer || {}).start,
|
|
||||||
end: (($scope.ngModel || {}).outer || {}).end
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateOuterStart(t) {
|
|
||||||
var ngModel = $scope.ngModel;
|
|
||||||
|
|
||||||
ngModel.inner.start =
|
|
||||||
Math.max(ngModel.outer.start, ngModel.inner.start);
|
|
||||||
ngModel.inner.end = Math.max(
|
|
||||||
ngModel.inner.start + innerMinimumSpan,
|
|
||||||
ngModel.inner.end
|
|
||||||
);
|
|
||||||
|
|
||||||
updateFormModel();
|
|
||||||
updateViewForInnerSpanFromModel(ngModel);
|
|
||||||
updateTicks();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateOuterEnd(t) {
|
|
||||||
var ngModel = $scope.ngModel;
|
|
||||||
|
|
||||||
ngModel.inner.end =
|
|
||||||
Math.min(ngModel.outer.end, ngModel.inner.end);
|
|
||||||
ngModel.inner.start = Math.min(
|
|
||||||
ngModel.inner.end - innerMinimumSpan,
|
|
||||||
ngModel.inner.start
|
|
||||||
);
|
|
||||||
|
|
||||||
updateFormModel();
|
|
||||||
updateViewForInnerSpanFromModel(ngModel);
|
|
||||||
updateTicks();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateFormat(key) {
|
|
||||||
formatter = formatService.getFormat(key || defaultFormat);
|
|
||||||
updateViewForInnerSpanFromModel($scope.ngModel);
|
|
||||||
updateTicks();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBoundsFromForm() {
|
|
||||||
var start = $scope.formModel.start,
|
|
||||||
end = $scope.formModel.end;
|
|
||||||
if (end >= start + outerMinimumSpan) {
|
|
||||||
$scope.ngModel = $scope.ngModel || {};
|
|
||||||
$scope.ngModel.outer = { start: start, end: end };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateStart(startValue) {
|
|
||||||
return startValue <= $scope.formModel.end - outerMinimumSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateEnd(endValue) {
|
|
||||||
return endValue >= $scope.formModel.start + outerMinimumSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.startLeftDrag = startLeftDrag;
|
|
||||||
$scope.startRightDrag = startRightDrag;
|
|
||||||
$scope.startMiddleDrag = startMiddleDrag;
|
|
||||||
$scope.leftDrag = leftDrag;
|
|
||||||
$scope.rightDrag = rightDrag;
|
|
||||||
$scope.middleDrag = middleDrag;
|
|
||||||
|
|
||||||
$scope.updateBoundsFromForm = updateBoundsFromForm;
|
|
||||||
|
|
||||||
$scope.validateStart = validateStart;
|
|
||||||
$scope.validateEnd = validateEnd;
|
|
||||||
|
|
||||||
$scope.ticks = [];
|
|
||||||
|
|
||||||
// Initialize scope to defaults
|
|
||||||
updateViewFromModel($scope.ngModel);
|
|
||||||
updateFormModel();
|
|
||||||
|
|
||||||
$scope.$watchCollection("ngModel", updateViewFromModel);
|
|
||||||
$scope.$watch("spanWidth", updateSpanWidth);
|
|
||||||
$scope.$watch("ngModel.outer.start", updateOuterStart);
|
|
||||||
$scope.$watch("ngModel.outer.end", updateOuterEnd);
|
|
||||||
$scope.$watch("parameters.format", updateFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TimeRangeController;
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
function clamp(value, low, high) {
|
||||||
|
return Math.max(low, Math.min(high, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyBounds(bounds) {
|
||||||
|
return {
|
||||||
|
start: bounds.start,
|
||||||
|
end: bounds.end
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller used by the `time-controller` template.
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
|
* @constructor
|
||||||
|
* @param $scope the Angular scope for this controller
|
||||||
|
* @param {FormatService} formatService the service to user to format
|
||||||
|
* domain values
|
||||||
|
* @param {string} defaultFormat the format to request when no
|
||||||
|
* format has been otherwise specified
|
||||||
|
* @param {Function} now a function to return current system time
|
||||||
|
*/
|
||||||
|
function TimeRangeController($scope, formatService, defaultFormat, now) {
|
||||||
|
this.$scope = $scope;
|
||||||
|
this.formatService = formatService;
|
||||||
|
this.defaultFormat = defaultFormat;
|
||||||
|
this.now = now;
|
||||||
|
|
||||||
|
this.tickCount = 2;
|
||||||
|
this.innerMinimumSpan = 1000; // 1 second
|
||||||
|
this.outerMinimumSpan = 1000; // 1 second
|
||||||
|
this.initialDragValue = undefined;
|
||||||
|
this.formatter = formatService.getFormat(defaultFormat);
|
||||||
|
this.formStartChanged = false;
|
||||||
|
this.formEndChanged = false;
|
||||||
|
|
||||||
|
this.$scope.ticks = [];
|
||||||
|
|
||||||
|
this.updateViewFromModel(this.$scope.ngModel);
|
||||||
|
this.updateFormModel();
|
||||||
|
|
||||||
|
[
|
||||||
|
'updateViewFromModel',
|
||||||
|
'updateSpanWidth',
|
||||||
|
'updateOuterStart',
|
||||||
|
'updateOuterEnd',
|
||||||
|
'updateFormat',
|
||||||
|
'validateStart',
|
||||||
|
'validateEnd',
|
||||||
|
'onFormStartChange',
|
||||||
|
'onFormEndChange'
|
||||||
|
].forEach(function (boundFn) {
|
||||||
|
this[boundFn] = this[boundFn].bind(this);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.$scope.$watchCollection("ngModel", this.updateViewFromModel);
|
||||||
|
this.$scope.$watch("spanWidth", this.updateSpanWidth);
|
||||||
|
this.$scope.$watch("ngModel.outer.start", this.updateOuterStart);
|
||||||
|
this.$scope.$watch("ngModel.outer.end", this.updateOuterEnd);
|
||||||
|
this.$scope.$watch("parameters.format", this.updateFormat);
|
||||||
|
this.$scope.$watch("formModel.start", this.onFormStartChange);
|
||||||
|
this.$scope.$watch("formModel.end", this.onFormEndChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeRangeController.prototype.formatTimestamp = function (ts) {
|
||||||
|
return this.formatter.format(ts);
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateTicks = function () {
|
||||||
|
var i, p, ts, start, end, span;
|
||||||
|
end = this.$scope.ngModel.outer.end;
|
||||||
|
start = this.$scope.ngModel.outer.start;
|
||||||
|
span = end - start;
|
||||||
|
this.$scope.ticks = [];
|
||||||
|
for (i = 0; i < this.tickCount; i += 1) {
|
||||||
|
p = i / (this.tickCount - 1);
|
||||||
|
ts = p * span + start;
|
||||||
|
this.$scope.ticks.push(this.formatTimestamp(ts));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateSpanWidth = function (w) {
|
||||||
|
this.tickCount = Math.max(Math.floor(w / TICK_SPACING_PX), 2);
|
||||||
|
this.updateTicks();
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateViewForInnerSpanFromModel = function (
|
||||||
|
ngModel
|
||||||
|
) {
|
||||||
|
var span = ngModel.outer.end - ngModel.outer.start;
|
||||||
|
|
||||||
|
// Expose readable dates for the knobs
|
||||||
|
this.$scope.startInnerText = this.formatTimestamp(ngModel.inner.start);
|
||||||
|
this.$scope.endInnerText = this.formatTimestamp(ngModel.inner.end);
|
||||||
|
|
||||||
|
// And positions for the knobs
|
||||||
|
this.$scope.startInnerPct =
|
||||||
|
toPercent((ngModel.inner.start - ngModel.outer.start) / span);
|
||||||
|
this.$scope.endInnerPct =
|
||||||
|
toPercent((ngModel.outer.end - ngModel.inner.end) / span);
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.defaultBounds = function () {
|
||||||
|
var t = this.now();
|
||||||
|
return {
|
||||||
|
start: t - 24 * 3600 * 1000, // One day
|
||||||
|
end: t
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateViewFromModel = function (ngModel) {
|
||||||
|
ngModel = ngModel || {};
|
||||||
|
ngModel.outer = ngModel.outer || this.defaultBounds();
|
||||||
|
ngModel.inner = ngModel.inner || copyBounds(ngModel.outer);
|
||||||
|
|
||||||
|
// Stick it back is scope (in case we just set defaults)
|
||||||
|
this.$scope.ngModel = ngModel;
|
||||||
|
|
||||||
|
this.updateViewForInnerSpanFromModel(ngModel);
|
||||||
|
this.updateTicks();
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.startLeftDrag = function () {
|
||||||
|
this.initialDragValue = this.$scope.ngModel.inner.start;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.startRightDrag = function () {
|
||||||
|
this.initialDragValue = this.$scope.ngModel.inner.end;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.startMiddleDrag = function () {
|
||||||
|
this.initialDragValue = {
|
||||||
|
start: this.$scope.ngModel.inner.start,
|
||||||
|
end: this.$scope.ngModel.inner.end
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.toMillis = function (pixels) {
|
||||||
|
var span =
|
||||||
|
this.$scope.ngModel.outer.end - this.$scope.ngModel.outer.start;
|
||||||
|
return (pixels / this.$scope.spanWidth) * span;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.leftDrag = function (pixels) {
|
||||||
|
var delta = this.toMillis(pixels);
|
||||||
|
this.$scope.ngModel.inner.start = clamp(
|
||||||
|
this.initialDragValue + delta,
|
||||||
|
this.$scope.ngModel.outer.start,
|
||||||
|
this.$scope.ngModel.inner.end - this.innerMinimumSpan
|
||||||
|
);
|
||||||
|
this.updateViewFromModel(this.$scope.ngModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.rightDrag = function (pixels) {
|
||||||
|
var delta = this.toMillis(pixels);
|
||||||
|
this.$scope.ngModel.inner.end = clamp(
|
||||||
|
this.initialDragValue + delta,
|
||||||
|
this.$scope.ngModel.inner.start + this.innerMinimumSpan,
|
||||||
|
this.$scope.ngModel.outer.end
|
||||||
|
);
|
||||||
|
this.updateViewFromModel(this.$scope.ngModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.middleDrag = function (pixels) {
|
||||||
|
var delta = this.toMillis(pixels),
|
||||||
|
edge = delta < 0 ? 'start' : 'end',
|
||||||
|
opposite = delta < 0 ? 'end' : 'start';
|
||||||
|
|
||||||
|
// Adjust the position of the edge in the direction of drag
|
||||||
|
this.$scope.ngModel.inner[edge] = clamp(
|
||||||
|
this.initialDragValue[edge] + delta,
|
||||||
|
this.$scope.ngModel.outer.start,
|
||||||
|
this.$scope.ngModel.outer.end
|
||||||
|
);
|
||||||
|
// Adjust opposite knob to maintain span
|
||||||
|
this.$scope.ngModel.inner[opposite] =
|
||||||
|
this.$scope.ngModel.inner[edge] +
|
||||||
|
this.initialDragValue[opposite] -
|
||||||
|
this.initialDragValue[edge];
|
||||||
|
|
||||||
|
this.updateViewFromModel(this.$scope.ngModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateFormModel = function () {
|
||||||
|
this.$scope.formModel = {
|
||||||
|
start: ((this.$scope.ngModel || {}).outer || {}).start,
|
||||||
|
end: ((this.$scope.ngModel || {}).outer || {}).end
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateOuterStart = function () {
|
||||||
|
var ngModel = this.$scope.ngModel;
|
||||||
|
|
||||||
|
ngModel.inner.start =
|
||||||
|
Math.max(ngModel.outer.start, ngModel.inner.start);
|
||||||
|
ngModel.inner.end = Math.max(
|
||||||
|
ngModel.inner.start + this.innerMinimumSpan,
|
||||||
|
ngModel.inner.end
|
||||||
|
);
|
||||||
|
|
||||||
|
this.updateFormModel();
|
||||||
|
this.updateViewForInnerSpanFromModel(ngModel);
|
||||||
|
this.updateTicks();
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateOuterEnd = function () {
|
||||||
|
var ngModel = this.$scope.ngModel;
|
||||||
|
|
||||||
|
ngModel.inner.end =
|
||||||
|
Math.min(ngModel.outer.end, ngModel.inner.end);
|
||||||
|
ngModel.inner.start = Math.min(
|
||||||
|
ngModel.inner.end - this.innerMinimumSpan,
|
||||||
|
ngModel.inner.start
|
||||||
|
);
|
||||||
|
|
||||||
|
this.updateFormModel();
|
||||||
|
this.updateViewForInnerSpanFromModel(ngModel);
|
||||||
|
this.updateTicks();
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateFormat = function (key) {
|
||||||
|
this.formatter = this.formatService.getFormat(key || this.defaultFormat);
|
||||||
|
this.updateViewForInnerSpanFromModel(this.$scope.ngModel);
|
||||||
|
this.updateTicks();
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.updateBoundsFromForm = function () {
|
||||||
|
if (this.formStartChanged) {
|
||||||
|
this.$scope.ngModel.outer.start =
|
||||||
|
this.$scope.ngModel.inner.start =
|
||||||
|
this.$scope.formModel.start;
|
||||||
|
this.formStartChanged = false;
|
||||||
|
}
|
||||||
|
if (this.formEndChanged) {
|
||||||
|
this.$scope.ngModel.outer.end =
|
||||||
|
this.$scope.ngModel.inner.end =
|
||||||
|
this.$scope.formModel.end;
|
||||||
|
this.formEndChanged = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.onFormStartChange = function (
|
||||||
|
newValue,
|
||||||
|
oldValue
|
||||||
|
) {
|
||||||
|
if (!this.formStartChanged && newValue !== oldValue) {
|
||||||
|
this.formStartChanged = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.onFormEndChange = function (
|
||||||
|
newValue,
|
||||||
|
oldValue
|
||||||
|
) {
|
||||||
|
if (!this.formEndChanged && newValue !== oldValue) {
|
||||||
|
this.formEndChanged = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.validateStart = function (startValue) {
|
||||||
|
return startValue <=
|
||||||
|
this.$scope.formModel.end - this.outerMinimumSpan;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeRangeController.prototype.validateEnd = function (endValue) {
|
||||||
|
return endValue >=
|
||||||
|
this.$scope.formModel.start + this.outerMinimumSpan;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TimeRangeController;
|
||||||
|
});
|
||||||
|
@ -94,18 +94,18 @@ define(
|
|||||||
it("exposes start time validator", function () {
|
it("exposes start time validator", function () {
|
||||||
var testValue = 42000000;
|
var testValue = 42000000;
|
||||||
mockScope.formModel = { end: testValue };
|
mockScope.formModel = { end: testValue };
|
||||||
expect(mockScope.validateStart(testValue + 1))
|
expect(controller.validateStart(testValue + 1))
|
||||||
.toBe(false);
|
.toBe(false);
|
||||||
expect(mockScope.validateStart(testValue - 60 * 60 * 1000 - 1))
|
expect(controller.validateStart(testValue - 60 * 60 * 1000 - 1))
|
||||||
.toBe(true);
|
.toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("exposes end time validator", function () {
|
it("exposes end time validator", function () {
|
||||||
var testValue = 42000000;
|
var testValue = 42000000;
|
||||||
mockScope.formModel = { start: testValue };
|
mockScope.formModel = { start: testValue };
|
||||||
expect(mockScope.validateEnd(testValue - 1))
|
expect(controller.validateEnd(testValue - 1))
|
||||||
.toBe(false);
|
.toBe(false);
|
||||||
expect(mockScope.validateEnd(testValue + 60 * 60 * 1000 + 1))
|
expect(controller.validateEnd(testValue + 60 * 60 * 1000 + 1))
|
||||||
.toBe(true);
|
.toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -119,25 +119,87 @@ define(
|
|||||||
start: DAY * 10000,
|
start: DAY * 10000,
|
||||||
end: DAY * 11000
|
end: DAY * 11000
|
||||||
};
|
};
|
||||||
// These watches may not exist, but Angular would fire
|
});
|
||||||
// them if they did.
|
|
||||||
|
it('updates all changed bounds when requested', function () {
|
||||||
fireWatchCollection("formModel", mockScope.formModel);
|
fireWatchCollection("formModel", mockScope.formModel);
|
||||||
fireWatch("formModel.start", mockScope.formModel.start);
|
fireWatch("formModel.start", mockScope.formModel.start);
|
||||||
fireWatch("formModel.end", mockScope.formModel.end);
|
fireWatch("formModel.end", mockScope.formModel.end);
|
||||||
});
|
|
||||||
|
|
||||||
it("does not immediately make changes to the model", function () {
|
|
||||||
expect(mockScope.ngModel.outer.start)
|
expect(mockScope.ngModel.outer.start)
|
||||||
.not.toEqual(mockScope.formModel.start);
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
expect(mockScope.ngModel.inner.start)
|
||||||
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
|
||||||
expect(mockScope.ngModel.outer.end)
|
expect(mockScope.ngModel.outer.end)
|
||||||
.not.toEqual(mockScope.formModel.end);
|
.not.toEqual(mockScope.formModel.end);
|
||||||
|
expect(mockScope.ngModel.inner.end)
|
||||||
|
.not.toEqual(mockScope.formModel.end);
|
||||||
|
|
||||||
|
controller.updateBoundsFromForm();
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.start)
|
||||||
|
.toEqual(mockScope.formModel.start);
|
||||||
|
expect(mockScope.ngModel.inner.start)
|
||||||
|
.toEqual(mockScope.formModel.start);
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.end)
|
||||||
|
.toEqual(mockScope.formModel.end);
|
||||||
|
expect(mockScope.ngModel.inner.end)
|
||||||
|
.toEqual(mockScope.formModel.end);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates changed start bound when requested', function () {
|
||||||
|
fireWatchCollection("formModel", mockScope.formModel);
|
||||||
|
fireWatch("formModel.start", mockScope.formModel.start);
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.start)
|
||||||
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
expect(mockScope.ngModel.inner.start)
|
||||||
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.end)
|
||||||
|
.not.toEqual(mockScope.formModel.end);
|
||||||
|
expect(mockScope.ngModel.inner.end)
|
||||||
|
.not.toEqual(mockScope.formModel.end);
|
||||||
|
|
||||||
|
controller.updateBoundsFromForm();
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.start)
|
||||||
|
.toEqual(mockScope.formModel.start);
|
||||||
|
expect(mockScope.ngModel.inner.start)
|
||||||
|
.toEqual(mockScope.formModel.start);
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.end)
|
||||||
|
.not.toEqual(mockScope.formModel.end);
|
||||||
|
expect(mockScope.ngModel.inner.end)
|
||||||
|
.not.toEqual(mockScope.formModel.end);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates model bounds on request", function () {
|
it('updates changed end bound when requested', function () {
|
||||||
mockScope.updateBoundsFromForm();
|
fireWatchCollection("formModel", mockScope.formModel);
|
||||||
|
fireWatch("formModel.end", mockScope.formModel.end);
|
||||||
|
|
||||||
expect(mockScope.ngModel.outer.start)
|
expect(mockScope.ngModel.outer.start)
|
||||||
.toEqual(mockScope.formModel.start);
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
expect(mockScope.ngModel.inner.start)
|
||||||
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
|
||||||
expect(mockScope.ngModel.outer.end)
|
expect(mockScope.ngModel.outer.end)
|
||||||
|
.not.toEqual(mockScope.formModel.end);
|
||||||
|
expect(mockScope.ngModel.inner.end)
|
||||||
|
.not.toEqual(mockScope.formModel.end);
|
||||||
|
|
||||||
|
controller.updateBoundsFromForm();
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.start)
|
||||||
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
expect(mockScope.ngModel.inner.start)
|
||||||
|
.not.toEqual(mockScope.formModel.start);
|
||||||
|
|
||||||
|
expect(mockScope.ngModel.outer.end)
|
||||||
|
.toEqual(mockScope.formModel.end);
|
||||||
|
expect(mockScope.ngModel.inner.end)
|
||||||
.toEqual(mockScope.formModel.end);
|
.toEqual(mockScope.formModel.end);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -160,27 +222,27 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("updates the start time for left drags", function () {
|
it("updates the start time for left drags", function () {
|
||||||
mockScope.startLeftDrag();
|
controller.startLeftDrag();
|
||||||
mockScope.leftDrag(250);
|
controller.leftDrag(250);
|
||||||
expect(mockScope.ngModel.inner.start)
|
expect(mockScope.ngModel.inner.start)
|
||||||
.toEqual(DAY * 1000 + HOUR * 9);
|
.toEqual(DAY * 1000 + HOUR * 9);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates the end time for right drags", function () {
|
it("updates the end time for right drags", function () {
|
||||||
mockScope.startRightDrag();
|
controller.startRightDrag();
|
||||||
mockScope.rightDrag(-250);
|
controller.rightDrag(-250);
|
||||||
expect(mockScope.ngModel.inner.end)
|
expect(mockScope.ngModel.inner.end)
|
||||||
.toEqual(DAY * 1000 + HOUR * 15);
|
.toEqual(DAY * 1000 + HOUR * 15);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates both start and end for middle drags", function () {
|
it("updates both start and end for middle drags", function () {
|
||||||
mockScope.startMiddleDrag();
|
controller.startMiddleDrag();
|
||||||
mockScope.middleDrag(-125);
|
controller.middleDrag(-125);
|
||||||
expect(mockScope.ngModel.inner).toEqual({
|
expect(mockScope.ngModel.inner).toEqual({
|
||||||
start: DAY * 1000,
|
start: DAY * 1000,
|
||||||
end: DAY * 1000 + HOUR * 18
|
end: DAY * 1000 + HOUR * 18
|
||||||
});
|
});
|
||||||
mockScope.middleDrag(250);
|
controller.middleDrag(250);
|
||||||
expect(mockScope.ngModel.inner).toEqual({
|
expect(mockScope.ngModel.inner).toEqual({
|
||||||
start: DAY * 1000 + HOUR * 6,
|
start: DAY * 1000 + HOUR * 6,
|
||||||
end: DAY * 1001
|
end: DAY * 1001
|
||||||
@ -188,8 +250,8 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("enforces a minimum inner span", function () {
|
it("enforces a minimum inner span", function () {
|
||||||
mockScope.startRightDrag();
|
controller.startRightDrag();
|
||||||
mockScope.rightDrag(-9999999);
|
controller.rightDrag(-9999999);
|
||||||
expect(mockScope.ngModel.inner.end)
|
expect(mockScope.ngModel.inner.end)
|
||||||
.toBeGreaterThan(mockScope.ngModel.inner.start);
|
.toBeGreaterThan(mockScope.ngModel.inner.start);
|
||||||
});
|
});
|
||||||
|
@ -6,6 +6,6 @@
|
|||||||
ng-model='ngModel'
|
ng-model='ngModel'
|
||||||
field="'domain'"
|
field="'domain'"
|
||||||
options="ngModel.options"
|
options="ngModel.options"
|
||||||
style="position: absolute; right: 0px; bottom: 46px;"
|
class="l-time-domain-selector"
|
||||||
>
|
>
|
||||||
</mct-control>
|
</mct-control>
|
||||||
|
Reference in New Issue
Block a user