diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index c979f03a47..55bddd712f 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -36,6 +36,8 @@ define( */ function TimeConductorController($scope, now) { var tickCount = 2, + innerMinimumSpan = 1000, // 1 second + outerMinimumSpan = 1000 * 60 * 60, // 1 hour initialDragValue; function formatTimestamp(ts) { @@ -140,7 +142,7 @@ define( $scope.ngModel.inner.start = clamp( initialDragValue + delta, $scope.ngModel.outer.start, - $scope.ngModel.inner.end + $scope.ngModel.inner.end - innerMinimumSpan ); updateViewFromModel($scope.ngModel); } @@ -149,7 +151,7 @@ define( var delta = toMillis(pixels); $scope.ngModel.inner.end = clamp( initialDragValue + delta, - $scope.ngModel.inner.start, + $scope.ngModel.inner.start + innerMinimumSpan, $scope.ngModel.outer.end ); updateViewFromModel($scope.ngModel); @@ -175,12 +177,18 @@ define( function updateOuterStart(t) { var ngModel = $scope.ngModel; - ngModel.outer.end = - Math.max(ngModel.outer.start, ngModel.outer.end); + + 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.outer.start, ngModel.inner.end); + ngModel.inner.end = Math.max( + ngModel.inner.start + innerMinimumSpan, + ngModel.inner.end + ); $scope.startOuterText = formatTimestamp(t); @@ -189,12 +197,18 @@ define( function updateOuterEnd(t) { var ngModel = $scope.ngModel; - ngModel.outer.start = - Math.min(ngModel.outer.end, ngModel.outer.start); - ngModel.inner.start = - Math.min(ngModel.outer.end, ngModel.inner.start); + + 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 + ); $scope.endOuterText = formatTimestamp(t); diff --git a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js index 48411756b0..9d7a6a9f52 100644 --- a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js +++ b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js @@ -26,6 +26,11 @@ define( function (TimeRangeController) { "use strict"; + var SEC = 1000, + MIN = 60 * SEC, + HOUR = 60 * MIN, + DAY = 24 * HOUR; + describe("The TimeRangeController", function () { var mockScope, mockNow, @@ -61,6 +66,107 @@ define( .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); + }); + }); }); }