= 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;
@@ -249,6 +244,9 @@ define(
$scope.updateBoundsFromForm = updateBoundsFromForm;
+ $scope.validateStart = validateStart;
+ $scope.validateEnd = validateEnd;
+
$scope.ticks = [];
// Initialize scope to defaults
diff --git a/platform/commonUI/general/src/filters/ReverseFilter.js b/platform/commonUI/general/src/filters/ReverseFilter.js
new file mode 100644
index 0000000000..16ab9bc882
--- /dev/null
+++ b/platform/commonUI/general/src/filters/ReverseFilter.js
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * 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';
+
+ /**
+ * Implements the `reverse` filter, which reverses text strings.
+ * Useful in cases where text should be reversed for presentational
+ * reasons (e.g. in conjunction with CSS tricks involing text direction),
+ * allowing such behavior to be handled independently from the controller
+ * layer.
+ *
+ * @constructor
+ * @memberof platform/commonUI/general
+ */
+ function ReverseFilter() {
+ return function reverse(value) {
+ return value && value.toString().split('').reverse().join('');
+ };
+ }
+
+ return ReverseFilter;
+});
diff --git a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js
index 861f28ed45..efff87651f 100644
--- a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js
+++ b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js
@@ -91,6 +91,24 @@ define(
.toHaveBeenCalledWith("ngModel", jasmine.any(Function));
});
+ it("exposes start time validator", function () {
+ var testValue = 42000000;
+ mockScope.formModel = { end: testValue };
+ expect(mockScope.validateStart(testValue + 1))
+ .toBe(false);
+ expect(mockScope.validateStart(testValue - 60 * 60 * 1000 - 1))
+ .toBe(true);
+ });
+
+ it("exposes end time validator", function () {
+ var testValue = 42000000;
+ mockScope.formModel = { start: testValue };
+ expect(mockScope.validateEnd(testValue - 1))
+ .toBe(false);
+ expect(mockScope.validateEnd(testValue + 60 * 60 * 1000 + 1))
+ .toBe(true);
+ });
+
describe("when changes are made via form entry", function () {
beforeEach(function () {
mockScope.ngModel = {
@@ -194,26 +212,6 @@ define(
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;
diff --git a/platform/commonUI/general/test/filters/ReverseFilterSpec.js b/platform/commonUI/general/test/filters/ReverseFilterSpec.js
new file mode 100644
index 0000000000..91b770c5a8
--- /dev/null
+++ b/platform/commonUI/general/test/filters/ReverseFilterSpec.js
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * 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/filters/ReverseFilter'],
+ function (ReverseFilter) {
+ 'use strict';
+
+ describe("The reverse filter", function () {
+ var reverse;
+
+ beforeEach(function () {
+ reverse = new ReverseFilter();
+ });
+
+ it("reverses text", function () {
+ expect(reverse('foo')).toEqual('oof');
+ });
+
+ it("returns undefined for undefined inputs", function () {
+ expect(reverse(undefined)).toBeUndefined();
+ });
+ });
+ }
+);
diff --git a/platform/commonUI/general/test/suite.json b/platform/commonUI/general/test/suite.json
index 5f3cf8bc64..09d0bfd097 100644
--- a/platform/commonUI/general/test/suite.json
+++ b/platform/commonUI/general/test/suite.json
@@ -20,6 +20,7 @@
"directives/MCTScroll",
"directives/MCTSplitPane",
"directives/MCTSplitter",
+ "filters/ReverseFilter",
"services/Popup",
"services/PopupService",
"services/UrlService",
diff --git a/platform/commonUI/themes/espresso/res/css/theme-espresso.css b/platform/commonUI/themes/espresso/res/css/theme-espresso.css
index 9fea0a877b..f0f0e41445 100644
--- a/platform/commonUI/themes/espresso/res/css/theme-espresso.css
+++ b/platform/commonUI/themes/espresso/res/css/theme-espresso.css
@@ -4299,10 +4299,10 @@ textarea {
.field-hints,
.fields {
}
-
-
+
+
.field-hints {
-
+
}
*/ }
/* line 30, ../../../../general/res/sass/forms/_datetime.scss */
@@ -7329,6 +7329,8 @@ table {
/* line 267, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick,
.tick-label {
+ direction: rtl;
+ unicode-bidi: bidi-override;
font-size: 0.7rem;
position: absolute;
overflow: hidden;
diff --git a/platform/commonUI/themes/snow/res/css/theme-snow.css b/platform/commonUI/themes/snow/res/css/theme-snow.css
index 4866a5e379..2d227a1f87 100644
--- a/platform/commonUI/themes/snow/res/css/theme-snow.css
+++ b/platform/commonUI/themes/snow/res/css/theme-snow.css
@@ -4196,10 +4196,10 @@ textarea {
.field-hints,
.fields {
}
-
-
+
+
.field-hints {
-
+
}
*/ }
/* line 30, ../../../../general/res/sass/forms/_datetime.scss */
@@ -7202,6 +7202,8 @@ table {
/* line 267, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick,
.tick-label {
+ direction: rtl;
+ unicode-bidi: bidi-override;
font-size: 0.7rem;
position: absolute;
overflow: hidden;
diff --git a/platform/features/plot/res/templates/plot.html b/platform/features/plot/res/templates/plot.html
index 3dc50408ee..12680c2b27 100644
--- a/platform/features/plot/res/templates/plot.html
+++ b/platform/features/plot/res/templates/plot.html
@@ -47,7 +47,7 @@
- {{tick.label}}
+ {{tick.label | reverse}}
@@ -125,7 +125,7 @@
class="gl-plot-tick gl-plot-x-tick-label"
ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)"
ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%' }">
- {{tick.label}}
+ {{tick.label | reverse}}
{{axes[0].active.name}}
diff --git a/platform/framework/src/register/CustomRegistrars.js b/platform/framework/src/register/CustomRegistrars.js
index 0051105036..e47825e991 100644
--- a/platform/framework/src/register/CustomRegistrars.js
+++ b/platform/framework/src/register/CustomRegistrars.js
@@ -221,6 +221,13 @@ define(
CustomRegistrars.prototype.services =
mapUpon(customRegistrar("service"));
+ /**
+ * Register Angular filters.
+ * @param {Array} extensions the resolved extensions
+ */
+ CustomRegistrars.prototype.filters =
+ mapUpon(customRegistrar("filter"));
+
/**
* Register functions which will run after bootstrapping.
* @param {Array} extensions the resolved extensions